You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用transition-behavior: allow-discrete时,height反向过渡失效问题

问题根源

当元素被设为display: none时,它相当于从页面里“消失”了,浏览器不会保存它的任何布局状态。当你要展开它时,display先变回block,但这时候元素才刚被浏览器渲染出来,之前的height: 0状态根本没被记录,浏览器直接把高度拉到50px,自然就没过渡效果了。

transition-behavior: allow-discrete只能管收起的过程:先把高度缩到0,再隐藏元素。但展开时不行,因为元素隐藏的时候根本没布局数据,没法从0过渡到50px。

解决办法

要让展开收起都有平滑过渡,得手动控制样式变化的顺序:

  • 收起:先让高度过渡到0,等动画结束再设display: none
  • 展开:先把display改回block,等浏览器把元素渲染出来,再让高度过渡到50px

修改后的代码如下:

JS 代码

const toggle = () => {
  document.querySelectorAll('.thing').forEach(el => {
    if (el.classList.contains('closed')) {
      // 展开:先取消高度收起状态,强制浏览器渲染元素,再取消隐藏
      el.classList.remove('closed');
      void el.offsetHeight; // 触发重绘,确保元素已显示
      el.classList.remove('hidden');
    } else {
      // 收起:先触发高度过渡,动画结束后隐藏元素
      el.classList.add('closed');
      el.addEventListener('transitionend', function end() {
        el.classList.add('hidden');
        el.removeEventListener('transitionend', end);
      }, { once: true });
    }
  });
}

document.querySelector('button').addEventListener('click', toggle);

CSS 代码

.thing {
  overflow: hidden;
  height: 50px;
  transition: height 1s;
  outline: 1px solid blue;
}

.thing.closed {
  height: 0;
}

.thing.hidden {
  display: none;
}

HTML 代码

<div class="thing">
  I am thing
</div>

<div class="thing">
  I am a discrete thing
</div>

<button>Toggle</button>
关键说明
  • 用transitionend事件等高度动画跑完再隐藏元素,不会打断过渡过程
  • 展开时的void el.offsetHeight是核心,它强制浏览器立即重绘元素,确保元素已经在页面布局中,此时取消隐藏,高度就能从0平滑过渡到50px
  • 去掉了transition-behavior: allow-discrete,靠JS手动控制样式顺序,兼容性更强

内容的提问来源于stack exchange,提问作者DEfusion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 01:20:05