z-index不生效是因为元素未创建层叠上下文;需满足position非static且父级未封闭上下文,否则z-index仅在局部有效。

z-index不生效?先看它有没有“资格”参与层叠
Bootstrap 的 z-index 不是独立系统,它完全遵循 CSS 原生的层叠上下文(stacking context)规则。你设了 z-index: 9999 却被盖住,大概率不是 Bootstrap “没给够”,而是目标元素压根没获得参与层叠的资格。
- 必须有
position:static(默认值)元素无视z-index,哪怕写上也当没写;至少得是relative、absolute、fixed或sticky - 父级可能“封印”了你:如果父容器设置了
z-index(且非auto),或用了opacity、transform、filter等属性,它就创建了新的层叠上下文——你的z-index: 9999只在这个小圈子里有效,出不去 - Bootstrap 自己的层级是公开的:
.navbar是 1000,.modal是 1055,.tooltip是 1070,.toast是 1080。你自定义的下拉子菜单若没显式设值,就按默认文档流堆叠,大概率被压在下面
多级下拉菜单被遮挡?问题不在 z-index 数值大小
二级菜单消失,不是因为你没写够大的数字,而是它被卡在了错误的层叠上下文里。比如 .navbar 用了 transform 动画收起菜单,整个导航栏就成了一个独立层叠上下文,你再怎么给子菜单设 z-index: 9999,它也只能在 navbar 这个“盒子”里排第一,盒子本身还是被 .modal 盖着。
- 检查父容器是否触发了新层叠上下文:用浏览器开发者工具的「Layers」面板或勾选「Show stacking order」,一眼就能看到上下文边界
- 子菜单的
z-index必须比它的**直接父级层叠容器**高,而不是比全局最高值高。例如父级.dropdown-menu在.navbar(z=1000)内,那子菜单至少设z-index: 1001 - 别在子菜单上加
transform或opacity: 0.99——它们会悄悄新建一层上下文,让你刚设好的z-index失效
为什么 modal 里开 dropdown 总是失效?
因为 .modal 的 z-index: 1055 创建了一个强隔离的层叠上下文,而 Bootstrap 默认的 .dropdown-menu 没设 z-index(继承自父级或按文档流),自然掉到 modal 底下。这不是 bug,是设计使然——modal 要确保自己“绝对最上”,所有内容都得向它对齐。
- 手动补
z-index:给.dropdown-menu加z-index: 1056(比 modal 高 1 即可),但前提是它没被更上层的上下文包裹 - 警惕
transform:很多 navbar-collapse 或 offcanvas 组件靠transform实现动画,一旦启用,其内部所有 dropdown 都会被“关进笼子”,此时得把 dropdown 移到 modal 外部 DOM 位置,或用container: 'body'选项重定向渲染位置 - 移动端尤其明显:iOS Safari 对
hover+z-index组合极其敏感,纯 CSS 多级菜单在手机上基本不可靠,必须用 JS 控制show类
怎么查清到底谁在盖谁?
别猜,直接看。浏览器开发者工具里的「Computed」面板能显示最终生效的 z-index 和「Stacking Context」来源;「Layers」面板则可视化整个层叠树结构,一眼看出哪个元素是上下文根节点。
- 右键目标元素 → 「Inspect」→ 切到「Computed」→ 搜
z-index,看值是不是auto或具体数字 - 同页面打开「Layers」面板(Chrome DevTools → ⚙️ Settings → Experiments → 勾选 Layers),悬停元素即可看到它属于哪一层上下文
- 临时加
outline: 2px solid red辅助定位,比改background更不影响原有视觉逻辑
真正难的从来不是写多大的数字,而是看清当前这一片 DOM 树里,谁说了算、谁被谁管着。层叠上下文看不见摸不着,但它就在那儿,而且很固执。











