Bootstrap 5 tab 切换需用 opacity+visibility 替代 display 控制显隐,关键 CSS 为:.tab-content > .tab-pane {opacity:0;visibility:hidden;transition:opacity .3s ease,visibility .3s ease;}.tab-content > .tab-pane.show {opacity:1;visibility:visible;}
Bootstrap 5 的 tab-pane 切换默认靠 display: none 控制显隐,而 opacity 是不可过渡的——因为从 display: none 到 display: block 会中断 CSS 动画链。直接加 transition: opacity .3s 没用,面板会“闪现”,不是淡入。
必须让所有 tab-pane 始终在文档流中(即不用 display 切换),改用 opacity + visibility 配合控制。
.tab-pane 的 display 切换逻辑(需覆盖 JS 行为或用 CSS 强制)opacity: 0 时必须配 visibility: hidden,否则仍占交互区域opacity: 1 时设 visibility: visible,且确保 height 或 overflow 不导致布局跳动只写这几行就能生效,但顺序和选择器权重很重要:
.tab-content > .tab-pane { opacity: 0; visibility: hidden; transition: opacity .3s ease, visibility .3s ease;}.tab-content > .tab-pane.show { opacity: 1; visibility: visible;}
注意:.show 是 Bootstrap 切换时自动加在当前面板上的 class;> 子选择器防止样式污染嵌套 pane;visibility 必须和 opacity 同步过渡,否则会出现半透明可点击的“幽灵面板”。
立即学习“前端免费学习笔记(深入)”;
animation 替代 transition,它无法响应 JS 动态增删 .show
fade 类(如 <div class="tab-pane fade">),得先禁用它的 opacity: 0 和 transition,否则和你的规则冲突visibility + transition 支持稳定,但旧版 Android WebView 可能有渲染延迟Bootstrap 的 shown.bs.tab 事件触发时,.show 已被加上,但 DOM 重排可能未完成——如果你在事件回调里立刻操作 tab-pane 的子元素高度,可能拿不到正确值。
style.opacity,否则绕过 Bootstrap 状态管理show.bs.tab(显示前)里修改 opacity,此时面板还是隐藏态,强行设 opacity: 1 会破坏过渡起点tab.show()),确认它确实触发了 .show 类增删,而不是仅操作 style.display
这些浏览器不支持 visibility 的 transition,且对 opacity 过渡有渲染 bug:可能首帧卡在 0.99 而非平滑到 1,或过渡结束后残留模糊边框。
transform: translateZ(0) 强制硬件加速,缓解模糊visibility,改用 pointer-events: none 配合 opacity,但需额外处理键盘焦点(tabindex="-1")prefers-reduced-motion 或 UA,对老浏览器降级回无动画切换,而不是硬撑过渡真正难的不是写这三行 CSS,而是意识到:过渡效果必须和框架的状态更新节奏对齐,而不是和 DOM 显隐逻辑打架。稍一错位,就是半秒白屏或者点不动的 tab。