bootstrap 5 的 $z-index-map 是一个语义化 sass map,键为组件名(如 tooltip、modal),值为整数,默认 modal 和 toast 均为 1050,但 toast 因内联样式优先级更高而覆盖 modal。

Bootstrap 的 $zindex 变量体系不是“一张固定表格”,而是一组可推导、可覆盖的 Sass 层级映射;直接硬记数值或依赖默认值,在复杂弹层叠加(比如 Modal 里嵌 Tooltip 再叠 Toast)时必然出错。
Bootstrap 5 的 $z-index-map 是什么结构
它本质是一个 Sass map,键是语义化层级名(如 tooltip、popover、modal-backdrop),值是整数。默认起始值是 1000(modal),往上递增,往下递减:
$zindex-map: ( "tooltip": 1070, "popover": 1060, "toast": 1050, "modal-backdrop": 1040, "modal": 1050, "dropdown": 1000, "sticky": 1020, "fixed": 1030, "navbar": 1000, "nav-link": 1000, "jumbotron": 0, "gutter": 0 ) !default;
注意:modal 和 toast 都是 1050,但实际渲染中 toast 默认用 position: fixed + z-index 内联样式,会覆盖 CSS 规则中的同值声明 —— 这就是“为什么 Toast 总盖在 Modal 上”的底层原因。
覆盖 $zindex-map 的三种安全方式
别直接改 Bootstrap 源码里的 _variables.scss,否则升级就丢。推荐以下顺序尝试:
- 在自定义 Sass 文件中,重定义整个 map(必须在
@import "bootstrap"之前):$zindex-map: ( "tooltip": 1080, "popover": 1070, "toast": 1060, "modal-backdrop": 1040, "modal": 1050 );
- 只覆盖单个层级:用
map-merge(),更灵活$zindex-map: map-merge($zindex-map, ("toast": 1045)); - 运行时动态控制:对特定元素加内联
style="z-index: 1080;",但仅限临时调试 —— 它会绕过所有响应式逻辑和媒体查询适配
常见 z-index 失效场景及排查路径
不是数值不够大,而是 stacking context 被意外创建:
-
transform、filter、will-change、opacity 等属性会触发新 stacking context,导致子元素的 <code>z-index只在该 context 内生效 - 父容器用了
position: relative但没设z-index,子 Modal 就可能被隔壁卡片的z-index: 9999压住 - 多个第三方组件(如日期选择器 + 下拉菜单)各自维护自己的
$zindex变量,未统一协调 - 检查浏览器 DevTools 的 Layers 面板(Chrome > More Tools > Layers),看是否真有预期的 stacking context 分层
真正麻烦的从来不是“该设多少”,而是不同组件在不同上下文里悄悄创建 stacking context,又各自 hardcode 数值 —— 所以建议团队约定一个基础 $z-base 变量,所有扩展都基于它计算,比如 toast: $z-base + 50,而不是写死 1050。











