Bootstrap 5 通过 visibility + opacity + transform 组合替代 display 切换,避免重排、启用 GPU 加速;保留 .fade 类以同步 backdrop 与 dialog 动画;监听 transitionend 而非 setTimeout;动态内容需调用 handleUpdate();CSS 加载顺序影响动画生效。

因为 Bootstrap 5 不是“删掉 jQuery 就变快”,而是用原生 JS 精准接管了 CSS 动画的整个生命周期——从触发时机、属性选择,到状态判断,全都绕开了 display 切换、隐式重排和过渡封装陷阱。
为什么 display: none + show() 会卡顿
jQuery 风格的 $().modal('show') 内部通常先设 style.display = 'block',再加 opacity 过渡。但 display 切换会强制触发浏览器重排(reflow),打断 CSS 动画流水线,GPU 加速直接失效。
Bootstrap 5 改用 visibility: hidden + opacity + transform 组合:
- 三者都属于「仅触发重绘(repaint)」的属性,可被 GPU 加速
-
visibility控制显隐逻辑,不破坏文档流,也不阻断 transition - 动画开始前就确保元素已渲染、未被父级
display: none硬性隐藏
.modal.fade 必须保留,不能删
这个 class 不是可选装饰,它是 backdrop 和 dialog 动画同步的前提:
立即学习“前端免费学习笔记(深入)”;
- 删掉它,遮罩层(backdrop)可能闪现或淡入滞后,导致视觉撕裂
- 即使你加了
animate.css或自定义@keyframes,不同步照样白搭 -
.fade类里声明的transition: opacity .15s ease-in-out, transform .15s ease-in-out是被 JS 监听的依据
transitionend 事件监听比 setTimeout 精确得多
原生实现不再依赖 jQuery 的 fadeIn() 或定时器轮询,而是:
- 显式监听
transitionend事件,且只响应目标属性(如opacity) - 配合
getComputedStyle检查当前状态,避免“动画结束但样式未生效”的误判 - 必须写全属性:用
transition: opacity .15s, transform .15s,不能只写transition: all .15s(部分浏览器无法识别all中的transform)
动态内容加载后位置偏移?别忘了 handleUpdate()
如果 modal 内容高度是异步加载的(比如 fetch 后插入 DOM),Popper 定位不会自动重算:
- 动画开始前位置是对的,内容撑开后 dialog 偏移,但 backdrop 仍按旧尺寸铺满
- 必须在内容渲染完成后手动调用
myModal.handleUpdate() - 漏掉这步,
transform: translate()依然执行,但基准坐标错了,看起来像“抖动”或“错位”
最容易被忽略的是:CSS 文件加载顺序和 JS 执行时机。哪怕只差几毫秒,show() 调用时样式未就绪,transition 就会被跳过——这时候动画退化成硬切,所有优化归零。



















