admin管理员组文章数量:1023282
Trying to create a reusable collapse ponent, but having a smooth transition on the element getting a problem. So when the collapse item is clicked i want have a smooth transition
Here is the main part of what i have tried so far.
index.js
const Collapse = ({ title, text, child, ...props }) => {
const [isOpen, setIsOpen] = useState(false);
const toggleCollapse = () => setIsOpen((isOpen) => !isOpen);
const closeCollapse = () => setIsOpen(false);
const content = useRef(null);
const isParentOpen = props.isParentOpen;
useEffect(() => {
if (!isParentOpen) closeCollapse();
}, [isParentOpen]);
const height = !isOpen ? "0px" : `auto`; // ${content.current?.scrollHeight}px
return (
<CollapseContainer>
<CollapseButton isOpen={isOpen} onClick={toggleCollapse}>
<CollapseTitleWrapper>{title}</CollapseTitleWrapper>
</CollapseButton>
<CollapseContent ref={content} max_height={height}>
<CollapseText>
{text}
{child?.map((datumn, index) => (
<Collapse
{...datumn}
key={`collapse-child-${index}`}
isParentOpen={isOpen}
/>
))}
</CollapseText>
</CollapseContent>
</CollapseContainer>
);
};
export default Collapse;
So i am able to calculate the height of the content dynamically using ref, but smooth transition will happen but i will get a scroll inside the child collapse nested that i don't want. Is there way to apply transition on height:auto.
Here is the working codesandbox
Trying to create a reusable collapse ponent, but having a smooth transition on the element getting a problem. So when the collapse item is clicked i want have a smooth transition
Here is the main part of what i have tried so far.
index.js
const Collapse = ({ title, text, child, ...props }) => {
const [isOpen, setIsOpen] = useState(false);
const toggleCollapse = () => setIsOpen((isOpen) => !isOpen);
const closeCollapse = () => setIsOpen(false);
const content = useRef(null);
const isParentOpen = props.isParentOpen;
useEffect(() => {
if (!isParentOpen) closeCollapse();
}, [isParentOpen]);
const height = !isOpen ? "0px" : `auto`; // ${content.current?.scrollHeight}px
return (
<CollapseContainer>
<CollapseButton isOpen={isOpen} onClick={toggleCollapse}>
<CollapseTitleWrapper>{title}</CollapseTitleWrapper>
</CollapseButton>
<CollapseContent ref={content} max_height={height}>
<CollapseText>
{text}
{child?.map((datumn, index) => (
<Collapse
{...datumn}
key={`collapse-child-${index}`}
isParentOpen={isOpen}
/>
))}
</CollapseText>
</CollapseContent>
</CollapseContainer>
);
};
export default Collapse;
So i am able to calculate the height of the content dynamically using ref, but smooth transition will happen but i will get a scroll inside the child collapse nested that i don't want. Is there way to apply transition on height:auto.
Here is the working codesandbox
Share Improve this question asked Jun 5, 2021 at 6:33 devdev 9361 gold badge18 silver badges37 bronze badges 5- No you cannot transition to auto as is covered in many SO questions. It sounds like you need to switch off the overflow until needed. – Paulie_D Commented Jun 5, 2021 at 7:33
- So is there any other way to achieve this ? – dev Commented Jun 5, 2021 at 16:36
- @Paulie_D if i used onTransitionEnd event then on open of the accordion i will be able to show without scroll and a smooth transition event, but when closing it won't work is there any way to achieve this – dev Commented Jun 5, 2021 at 17:54
- You can do a smooth transition but for that you will need to make the height based on scrollHeight. So that's how you can get a dynamic height and write the transition on height. – moshfiqrony Commented Jun 7, 2021 at 9:09
- Are you open to installing an npm package to solve the problem? I've used this on several projects: npmjs./package/react-animate-height – Aaron Sarnat Commented Jun 12, 2021 at 9:29
4 Answers
Reset to default 2I think you should change the concept, it is doable simply with CSS animation that is way more optimized and allows you to create custom effects!
First we define two animations (is-open and is-closed) :
.is-open {
animation: is-open 0.3s ease both;
}
@keyframes is-open {
from {
opacity: 0;
transform: scaleY(0);
}
to {
opacity: 1;
transform: scaleY(1);
height: 100%;
}
}
and
.is-closed {
animation: is-closed 0.3s ease both;
}
@keyframes is-closed {
from {
opacity: 1;
transform: scaleY(1);
}
to {
opacity: 0;
transform: scaleY(0);
height: 0;
}
}
Now the only thing we need is a conditional class which handle these animations:
<CollapseContent
ref={content}
className={isOpen ? "is-open" : "is-closed"}
>
Check the result here.
it's impossible to use CSS animations with auto
keyword. A possible solution is to use height
instead of maxHeight
and overflow: hidden
and set height
to the auto
when animation is finished. I would remend using WAAPI(Web Animation API) as it simplifies using animations in js, and do not bubble events like css transitions.
here's an example: https://codesandbox.io/s/determined-curran-hsrm9?file=/src/Collapse/index.js
Use viewport units -> 100vh
. https://css-tricks./fun-viewport-units/
const height = !isOpen ? "0px" : `100vh`; // ${content.current?.scrollHeight}px
Also, to hide the temporary scrollbar, I applied overflow: hidden;
to export const CollapseContent = styled.div
Your codepen modified: https://codesandbox.io/s/strange-swirles-pebp1
Get the height of the element with:
Ref.current.getBoundingClientRect().height
The instant the transition starts add the style overflow:hidden
to prevent the scrollbar, then create a function that is called on the transitioned element using onTransitionEnd
to reactivate overflow when the transition has pleted (if needed).
Trying to create a reusable collapse ponent, but having a smooth transition on the element getting a problem. So when the collapse item is clicked i want have a smooth transition
Here is the main part of what i have tried so far.
index.js
const Collapse = ({ title, text, child, ...props }) => {
const [isOpen, setIsOpen] = useState(false);
const toggleCollapse = () => setIsOpen((isOpen) => !isOpen);
const closeCollapse = () => setIsOpen(false);
const content = useRef(null);
const isParentOpen = props.isParentOpen;
useEffect(() => {
if (!isParentOpen) closeCollapse();
}, [isParentOpen]);
const height = !isOpen ? "0px" : `auto`; // ${content.current?.scrollHeight}px
return (
<CollapseContainer>
<CollapseButton isOpen={isOpen} onClick={toggleCollapse}>
<CollapseTitleWrapper>{title}</CollapseTitleWrapper>
</CollapseButton>
<CollapseContent ref={content} max_height={height}>
<CollapseText>
{text}
{child?.map((datumn, index) => (
<Collapse
{...datumn}
key={`collapse-child-${index}`}
isParentOpen={isOpen}
/>
))}
</CollapseText>
</CollapseContent>
</CollapseContainer>
);
};
export default Collapse;
So i am able to calculate the height of the content dynamically using ref, but smooth transition will happen but i will get a scroll inside the child collapse nested that i don't want. Is there way to apply transition on height:auto.
Here is the working codesandbox
Trying to create a reusable collapse ponent, but having a smooth transition on the element getting a problem. So when the collapse item is clicked i want have a smooth transition
Here is the main part of what i have tried so far.
index.js
const Collapse = ({ title, text, child, ...props }) => {
const [isOpen, setIsOpen] = useState(false);
const toggleCollapse = () => setIsOpen((isOpen) => !isOpen);
const closeCollapse = () => setIsOpen(false);
const content = useRef(null);
const isParentOpen = props.isParentOpen;
useEffect(() => {
if (!isParentOpen) closeCollapse();
}, [isParentOpen]);
const height = !isOpen ? "0px" : `auto`; // ${content.current?.scrollHeight}px
return (
<CollapseContainer>
<CollapseButton isOpen={isOpen} onClick={toggleCollapse}>
<CollapseTitleWrapper>{title}</CollapseTitleWrapper>
</CollapseButton>
<CollapseContent ref={content} max_height={height}>
<CollapseText>
{text}
{child?.map((datumn, index) => (
<Collapse
{...datumn}
key={`collapse-child-${index}`}
isParentOpen={isOpen}
/>
))}
</CollapseText>
</CollapseContent>
</CollapseContainer>
);
};
export default Collapse;
So i am able to calculate the height of the content dynamically using ref, but smooth transition will happen but i will get a scroll inside the child collapse nested that i don't want. Is there way to apply transition on height:auto.
Here is the working codesandbox
Share Improve this question asked Jun 5, 2021 at 6:33 devdev 9361 gold badge18 silver badges37 bronze badges 5- No you cannot transition to auto as is covered in many SO questions. It sounds like you need to switch off the overflow until needed. – Paulie_D Commented Jun 5, 2021 at 7:33
- So is there any other way to achieve this ? – dev Commented Jun 5, 2021 at 16:36
- @Paulie_D if i used onTransitionEnd event then on open of the accordion i will be able to show without scroll and a smooth transition event, but when closing it won't work is there any way to achieve this – dev Commented Jun 5, 2021 at 17:54
- You can do a smooth transition but for that you will need to make the height based on scrollHeight. So that's how you can get a dynamic height and write the transition on height. – moshfiqrony Commented Jun 7, 2021 at 9:09
- Are you open to installing an npm package to solve the problem? I've used this on several projects: npmjs./package/react-animate-height – Aaron Sarnat Commented Jun 12, 2021 at 9:29
4 Answers
Reset to default 2I think you should change the concept, it is doable simply with CSS animation that is way more optimized and allows you to create custom effects!
First we define two animations (is-open and is-closed) :
.is-open {
animation: is-open 0.3s ease both;
}
@keyframes is-open {
from {
opacity: 0;
transform: scaleY(0);
}
to {
opacity: 1;
transform: scaleY(1);
height: 100%;
}
}
and
.is-closed {
animation: is-closed 0.3s ease both;
}
@keyframes is-closed {
from {
opacity: 1;
transform: scaleY(1);
}
to {
opacity: 0;
transform: scaleY(0);
height: 0;
}
}
Now the only thing we need is a conditional class which handle these animations:
<CollapseContent
ref={content}
className={isOpen ? "is-open" : "is-closed"}
>
Check the result here.
it's impossible to use CSS animations with auto
keyword. A possible solution is to use height
instead of maxHeight
and overflow: hidden
and set height
to the auto
when animation is finished. I would remend using WAAPI(Web Animation API) as it simplifies using animations in js, and do not bubble events like css transitions.
here's an example: https://codesandbox.io/s/determined-curran-hsrm9?file=/src/Collapse/index.js
Use viewport units -> 100vh
. https://css-tricks./fun-viewport-units/
const height = !isOpen ? "0px" : `100vh`; // ${content.current?.scrollHeight}px
Also, to hide the temporary scrollbar, I applied overflow: hidden;
to export const CollapseContent = styled.div
Your codepen modified: https://codesandbox.io/s/strange-swirles-pebp1
Get the height of the element with:
Ref.current.getBoundingClientRect().height
The instant the transition starts add the style overflow:hidden
to prevent the scrollbar, then create a function that is called on the transitioned element using onTransitionEnd
to reactivate overflow when the transition has pleted (if needed).
本文标签: javascriptnested dynamic height transition effectStack Overflow
版权声明:本文标题:javascript - nested dynamic height transition effect - Stack Overflow 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/questions/1745599660a2158380.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论