React中实现内容动态变化div的展开收起平滑过渡效果
动态内容展开/收起平滑过渡实现方案
针对高度为auto的动态CMS内容,有3种常用的无固定高度依赖的实现方案:
方案1:max-height 过渡(兼容性最好,无JS依赖)
该方案不需要提前知晓内容高度,仅需给容器设置一个远大于实际最大内容高度的max-height值,通过切换max-height的状态实现过渡:
- 收起状态设置
max-height: 短描述状态的实际高度,同时开启overflow: hidden,添加过渡属性transition: max-height 0.3s ease - 展开状态设置
max-height: 远大于站点所有可能的描述内容高度的数值(比如1000px,根据业务场景调整即可)
注意点:如果预估的max-height和实际内容高度差太多,会出现过渡速度不一致的问题,适合内容长度浮动不大的场景。
示例代码:
.desc-container { overflow: hidden; max-height: 60px; /* 短描述状态的固定高度 */ transition: max-height 0.3s ease; } .desc-container.expanded { max-height: 1000px; /* 确保大于站点所有可能的描述内容高度 */ }
方案2:CSS Grid 过渡(无高度预估,效果更丝滑)
该方案是近些年兼容性已经覆盖绝大多数用户的新方案,不需要预估高度,也可以纯CSS实现:
- 给外层容器用grid布局,收起状态设置
grid-template-rows: 0fr,内容会被自动压缩 - 展开状态设置
grid-template-rows: 1fr,同时给容器的子元素加min-height: 0避免内容溢出 - 过渡属性绑定
grid-template-rows即可
示例代码:
.desc-wrapper { display: grid; grid-template-rows: 0fr; overflow: hidden; transition: grid-template-rows 0.3s ease; } .desc-wrapper.expanded { grid-template-rows: 1fr; } .desc-content { min-height: 0; }
该方案对现代浏览器(Chrome 107+、Firefox 113+、Safari 16.1+)兼容性已经覆盖95%以上的用户,如果不需要兼容非常旧的浏览器优先选这个方案。
方案3:JS 动态计算高度(100%精准,无兼容问题)
如果内容长度浮动极大,又需要兼容旧浏览器,可以用JS动态读取内容的实际高度来设置:
- 收起状态默认高度设为短描述的高度,CSS过渡属性绑定height
- 点击切换展开时,先读取内容的
scrollHeight,把height设为这个值,过渡完成后再改回auto(避免窗口resize时内容溢出) - 点击切换收起时,先把height从auto改成当前的scrollHeight,下一帧再改成短描述高度触发过渡
示例代码:
const descEl = document.querySelector('.desc-container') const toggleBtn = document.querySelector('.toggle-btn') toggleBtn.addEventListener('click', () => { const isExpanded = descEl.classList.contains('expanded') if (isExpanded) { // 收起逻辑:先把auto改成当前实际高度 descEl.style.height = descEl.scrollHeight + 'px' // 下一帧触发过渡到收起高度 requestAnimationFrame(() => { descEl.style.height = '60px' // 短描述固定高度 descEl.classList.remove('expanded') }) } else { // 展开逻辑:设置为实际内容高度 descEl.style.height = descEl.scrollHeight + 'px' descEl.classList.add('expanded') // 过渡完成后改回auto,适配窗口resize setTimeout(() => { descEl.style.height = 'auto' }, 300) // 和CSS过渡时长保持一致 } })
.desc-container { overflow: hidden; height: 60px; /* 短描述固定高度 */ transition: height 0.3s ease; }
内容的提问来源于stack exchange,提问作者David Fox
相关产品推荐
相关产品推荐

