Collapse折叠动画高度怎么动态计算?

端木欧辰 阅读 52

我用原生JS写了个Collapse组件,但展开时高度固定写死了,内容一多就显示不全。试过用scrollHeight,但动画过程中高度变化会导致卡顿或者闪一下,不知道该怎么平滑处理?

这是我的结构:

<div class="collapse">
  <button onclick="toggle()">Toggle</button>
  <div class="content" style="height: 0; overflow: hidden; transition: height 0.3s;">
    <p>这里是动态内容...</p>
    <p>可能有很多行</p>
  </div>
</div>
我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
一晶晶
一晶晶 Lv1
content元素展开前先设置style.height = 'auto',获取scrollHeight后再设回固定值做动画,收起时直接用0。就这样。

function toggle() {
var el = document.querySelector('.content');
if (el.style.height === '0px' || el.style.height === '') {
el.style.height = 'auto';
var height = el.scrollHeight;
el.style.height = '0px';
setTimeout(() => el.style.height = height + 'px', 0);
} else {
el.style.height = '0px';
}
}
点赞
2026-03-31 11:03
Designer°玉曼
用 max-height 是最省事的方案,但容易踩坑——设大了关闭动画会延迟,设小了内容多了显示不全。

正确姿势是用 scrollHeight 配合强制重绘:

function toggle() {
const content = document.querySelector('.content');

if (content.style.height === '' || content.style.height === '0px') {
// 展开
content.style.height = content.scrollHeight + 'px';
} else {
// 收起
content.style.height = content.scrollHeight + 'px';
// 强制重绘,必须的
content.offsetHeight;
content.style.height = '0px';
}
}


关键点就是那行 content.offsetHeight,不加这行的话浏览器会优化掉第一句设置,动画直接从0到0,看起来就是闪一下。

如果还想要更丝滑,可以用 transitionend 事件在动画结束后把 height 设为 auto,避免内容动态变化时样式冲突:

content.addEventListener('transitionend', function handler(e) {
if (e.propertyName === 'height' && content.style.height !== '0px') {
content.style.height = 'auto';
}
content.removeEventListener('transitionend', handler);
});


还有个更 hack 的方案,完全用 CSS 的 grid 布局,根本不用算高度:

.collapse-content {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.3s;
}

.collapse-content > div {
overflow: hidden;
}

.collapse-content.open {
grid-template-rows: 1fr;
}


不过 grid 这个方案对旧浏览器兼容性一般,如果是面向现代浏览器的话可以直接用,代码能少写不少。
点赞
2026-03-18 08:01