伪元素默认渲染顺序为父元素内容→::before→子元素→::after,但视觉层叠由层叠上下文和z-index决定;::before与::after默认同层,需父容器定位、显式z-index及避免opacity等触发新层叠上下文才能精确控制叠层。

伪元素默认渲染顺序不等于层叠顺序
伪元素 ::before 和 ::after 在 DOM 中并不存在真实节点,浏览器按固定顺序“插入”它们:父元素内容 → ::before → 子元素 → ::after。但这只是**生成顺序(paint order)**,不是最终视觉层叠结果。真正决定谁盖住谁的,是**层叠上下文(stacking context)和 z-index 计算规则**。
常见误解是“写在后面的伪元素自动在上面”,实际中:::before 和 ::after 默认处于同一层叠上下文内,且都无定位、z-index 为 auto,此时它们会按声明顺序叠加——但仅当父容器没创建新层叠上下文时才可靠。一旦父元素带 transform、opacity: 0.99 或 will-change,它就悄悄建立独立层叠上下文,子伪元素的 z-index 就只在该上下文内生效,无法跨出去和兄弟元素比高低。
z-index 失效的三个典型原因
给 ::before 设了 z-index: -1 却还是盖着文字?大概率踩了以下任一坑:
- 父容器没设
position: relative(或其它非static值),导致伪元素的position: absolute脱离到根层叠上下文,z-index失去参照系 - 父容器本身已因
opacity、filter或transform创建了层叠上下文,子伪元素的z-index只在内部排序,对外无效 -
::before和::after都设了position: absolute,但没显式设z-index,此时它们按源码顺序堆叠,后声明的(::after)默认压在先声明的(::before)之上
多伪元素叠加必须满足的硬性条件
想让 ::before、真实子元素、::after 三者严格按 z-index 排序,需同时满足:
- 父容器设
position: relative(哪怕不偏移,只为建立定位上下文) - 所有参与叠层的元素(含伪元素)都设
position为absolute、relative或fixed - 每个伪元素都显式声明
z-index(如z-index: 1、z-index: 2),不能依赖默认值 - 避免在父容器上用
opacity或transform——若必须用,改用background-color: rgba()替代透明度控制
为什么用 opacity 控制透明度会让层叠变混乱
直接对伪元素设 opacity: 0.5 看似简单,但它会把整个伪元素及其所有后代(哪怕为空)一起变透,且多层叠加时透明度相乘(两层 0.5 → 实际透出 0.25),颜色发灰、层次感丢失。更关键的是:opacity 会触发新层叠上下文,使该伪元素内部的 z-index 失效。
正确做法是用 background-color: rgba(0, 0, 0, 0.1) 或 background-image: linear-gradient(rgba(), rgba()), url(...) 控制单层背景透明度。这样既不影响层叠上下文,又避免颜色混叠,各层保持独立可调。
复杂点在于:层叠不是纯数值游戏,而是上下文嵌套 + 定位约束 + 渲染顺序三者咬合的结果。漏掉任意一环,z-index 就成摆设。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











