transitionEnd回调中用requestAnimationFrame修改display加CSS过渡失效问题
核心问题背景
将元素display属性从none改为block/flex等取值后,CSS过渡无法触发是前端常见问题,业界通用可行方案是使用requestAnimationFrame等待重排完成后再修改过渡属性,从而触发预期的动画效果。
方案失效的特殊场景
该通用方案在transitionend事件回调中执行时会失效,单次requestAnimationFrame无法触发预期过渡:
- 基础复现场景:设置红蓝两个默认
display: none的盒子,使用通用方案淡入蓝色盒子可正常生效 - 异常表现:监听蓝色盒子的
transitionend事件,触发后隐藏蓝色盒子,用相同逻辑显示红色盒子,红色盒子会直接显示,无opacity过渡效果 - 对照案例:给红色盒子绑定
onClick事件,用相同逻辑重新触发过渡可正常生效
复现代码
JS 代码
let elem = document.getElementById("elem"); let elem2 = document.getElementById("elem2"); function addFadeElem2() { elem2.classList.add("fade"); } function switchElements() { elem.classList.remove("fade") ; elem2.style.display = "block"; window.requestAnimationFrame(addFadeElem2); } elem.style.display = "block"; window.requestAnimationFrame(() => { elem.classList.add("fade"); }); function onTransitionEnd() { switchElements(); //elem.offsetHeight; // 开启该行强制重排即可正常运行 elem.removeEventListener("transitionend", onTransitionEnd); } elem.addEventListener("transitionend", onTransitionEnd); function refade() { elem2.style.display = "none"; elem2.classList.remove("fade"); window.requestAnimationFrame(() => { elem2.style.display = "block"; window.requestAnimationFrame(addFadeElem2); }); }
CSS 代码
#elem { background-color: blue; } #elem2 { background-color: red; } .box { display: none; opacity : 0; transition: opacity 1s; transition-timing-function: ease-in; width: 300px; height: 250px; } .box.fade { transition-timing-function: ease-out; opacity: 1; }
HTML 代码
<div id="elem" class="box">aaaaa</div> <div id="elem2" class="box" onclick="refade()">bbbbbbb</div>
已验证的可行解决方案
- 强制重排:设置
display: block后通过访问offsetHeight属性主动触发重排,无需requestAnimationFrame即可正常触发过渡 - 双
requestAnimationFrame:嵌套两层requestAnimationFrame回调执行属性修改,也可解决过渡失效问题
观察到的底层现象
通过开发者工具性能面板分析可得:过渡失效时,requestAnimationFrame回调在display: block对应的重排执行前就已经触发,导致过渡属性修改和display属性修改被合并到同一帧渲染,无前后状态差因此无法触发过渡。
待解答疑问
- 为什么
transitionend事件回调场景下会出现单次requestAnimationFrame失效的情况? - 为什么页面加载、点击事件场景下通用方案可以正常生效?
- 点击事件场景下方案生效,是否和
display: block是在requestAnimationFrame回调中设置有关?
内容的提问来源于stack exchange,提问作者Johnny Fang
相关产品推荐
相关产品推荐

