如何实现height从0到auto的平滑过渡,适配不确定高度的动态内容
适配动态高度的平滑展开解决方案
方案1:纯CSS实现(推荐,无额外JS)
利用CSS Grid的grid-template-rows属性实现,天然支持动态高度过渡,完全不需要固定值设置,适配任意长度的动态内容,过渡效果均匀平滑。
实现代码
#menu { cursor: pointer; } #list { /* 核心:用grid布局控制行高 */ display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.3s ease; overflow: hidden; background: #d5d5d5; } #menu:hover #list { grid-template-rows: 1fr; } /* 内部内容容器,边距放在这里避免收起时边距溢出 */ #list .content-inner { min-height: 0; margin: 0; padding: 12px; list-style: none; }
<div id="menu"> <a>hover over me</a> <div id="list"> <ul class="content-inner"> <!-- 动态渲染任意数量的条目 --> <li>item</li> <li>item</li> <li>item</li> </ul> </div> </div>
兼容性说明
Chrome 105+、Firefox 103+、Safari 16.4+ 均支持该特性,覆盖90%以上的全球用户。
方案2:轻量JS实现(全浏览器兼容)
如果需要兼容旧版本浏览器,可通过JS读取元素scrollHeight属性自动匹配高度,不需要手动计算条目高度,自动适配响应式场景。
实现代码
#list { max-height: 0; transition: max-height 0.3s ease, padding 0.3s ease; overflow: hidden; background: #d5d5d5; padding: 0 12px; } #list .content-inner { margin: 0; list-style: none; padding: 12px 0; }
<div id="menu"> <a>hover over me</a> <ul id="list" class="content-inner"> <!-- 动态渲染任意数量的条目 --> <li>item</li> <li>item</li> <li>item</li> </ul> </div>
const menu = document.querySelector('#menu') const list = document.querySelector('#list') // 展开逻辑 menu.addEventListener('mouseenter', () => { // 先设置为内容实际高度触发过渡 list.style.maxHeight = list.scrollHeight + 'px' list.style.paddingTop = '12px' list.style.paddingBottom = '12px' // 过渡完成后设置为auto,适配后续内容变化、窗口 resize 场景 setTimeout(() => { list.style.maxHeight = 'auto' }, 300) // 时长和CSS transition 保持一致 }) // 收起逻辑 menu.addEventListener('mouseleave', () => { // 先把auto转为当前实际高度,否则过渡无法生效 list.style.maxHeight = list.scrollHeight + 'px' // 强制浏览器重绘后再设置为0 requestAnimationFrame(() => { list.style.maxHeight = 0 list.style.paddingTop = 0 list.style.paddingBottom = 0 }) })
内容的提问来源于stack exchange,提问作者Sujit
相关产品推荐
相关产品推荐

