如何在添加动态内容时实现div高度平滑展开,无需设置固定高度
核心实现原理
CSS 原生 transition 不支持对 height: auto 做属性插值过渡,因此直接给容器加高度过渡不会生效。以下是两种适配动态内容高度的实现方案,无需固定高度即可实现平滑展开:
方案1:纯CSS Grid实现(推荐,无JS逻辑,适配所有动态高度)
无需计算内容高度,仅靠CSS即可实现任意高度内容的平滑过渡,现代浏览器兼容性优秀。
React 代码修改
const [isOpen, setIsOpen] = useState(false) const toggle = () => { setIsOpen(!isOpen) } return ( <div className="container"> <h1>TEST CONTAINER</h1> {/* 新增内容包裹层,不需要删除原有的条件渲染逻辑,也可以保留组件挂载状态 */} <div className={`content-wrapper ${isOpen ? 'open' : ''}`}> <Paragraph /> </div> <button type="button" class="btn btn-primary" onClick={toggle}>Primary</button> </div> ); }
CSS 代码修改
.container { margin-left: 30%; margin-top: 10%; width: 500px; height: auto; background-color: whitesmoke; } /* 内容包裹层样式 */ .content-wrapper { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.3s ease; overflow: hidden; } .content-wrapper.open { grid-template-rows: 1fr; } /* 可选:添加内容淡入效果,让过渡更自然 */ .content-wrapper > * { min-height: 0; opacity: 0; transition: opacity 0.2s ease 0.1s; } .content-wrapper.open > * { opacity: 1; }
方案2:JS动态计算高度(兼容性更好,适配低版本浏览器)
如果需要兼容不支持Grid过渡的低版本浏览器,可以用JS动态获取内容高度实现过渡,展开后自动切回height: auto不影响后续内容动态更新。
React 代码修改
import { useRef, useState, useEffect } from 'react'; const [isOpen, setIsOpen] = useState(false); const contentWrapperRef = useRef(null); const innerContentRef = useRef(null); const toggle = () => { setIsOpen(!isOpen); }; useEffect(() => { if (isOpen) { // 展开时读取内容实际高度触发过渡 const contentHeight = innerContentRef.current.scrollHeight; contentWrapperRef.current.style.height = `${contentHeight}px`; // 过渡结束后切回auto,适配后续内容高度变化 const onTransitionEnd = () => { contentWrapperRef.current.style.height = 'auto'; contentWrapperRef.current.removeEventListener('transitionend', onTransitionEnd); }; contentWrapperRef.current.addEventListener('transitionend', onTransitionEnd); } else { // 收起时先固定为当前高度再切为0触发过渡 contentWrapperRef.current.style.height = `${contentWrapperRef.current.scrollHeight}px`; // 强制浏览器重绘确保高度变更生效 void contentWrapperRef.current.offsetHeight; contentWrapperRef.current.style.height = '0px'; } }, [isOpen]); return ( <div className="container"> <h1>TEST CONTAINER</h1> <div ref={contentWrapperRef} className="dynamic-content-wrapper"> <div ref={innerContentRef}> <Paragraph /> </div> </div> <button type="button" class="btn btn-primary" onClick={toggle}>Primary</button> </div> ); }
CSS 代码修改
.container { margin-left: 30%; margin-top: 10%; width: 500px; height: auto; background-color: whitesmoke; } .dynamic-content-wrapper { height: 0; overflow: hidden; transition: height 0.3s ease; }
内容的提问来源于stack exchange,提问作者devAR
相关产品推荐
相关产品推荐

