参考文章
1. 基础规则:position: fixed 自动创建层叠上下文
position: fixed 自身就会创建新的层叠上下文,不需要再单独设置 z-index。 absolute 则必须显式指定 z-index 才会触发。
2. 用 nextZIndex 替代硬编码
禁止手动写死 z-index: 9999 之类的值,容易造成全局层级冲突。应当使用 Element Plus 提供的 useZIndex。
2.1 默认基准值
直接调用 nextZIndex() 时,返回值的基准默认是 2000,并在此基础上全局递增。
2.2 调用方式
在 onMounted 中初始化一次,不要在模板里直接调用,否则每次渲染都会递增。
import { useZIndex } from 'element-plus'
const { nextZIndex } = useZIndex()
const modalZIndex = ref(0)
onMounted(() => {
modalZIndex.value = nextZIndex() // 基于 2000 递增
})
3. 如何自定义全局基准值
如果想把基准值从默认的 2000 改成 3000(或其他值),用 <el-config-provider> 包裹组件树来提供 z-index:
<template>
<el-config-provider :z-index="3000">
<router-view />
</el-config-provider>
</template>
这样包裹后,内部所有调用 nextZIndex() 的地方都会基于 3000 开始递增。
⚠️ 注意:不要写成空的 <el-config-provider :z-index="3000" />(没有子元素),这会导致“全局污染”,让其他未包裹的组件也可能意外读到这个值。始终让 Provider 包裹实际需要接收配置的内容。
4. 局部层叠上下文(谨慎使用)
如果不想参与全局 z-index 竞争,可以用 isolation: isolate 创建局部层叠上下文:
.parent {
isolation: isolate;
}
⚠️ 副作用:内部的所有层叠元素(包括 position: fixed)将被限制在此上下文中,无法与外部全局层叠元素竞争。原本可以覆盖全屏的 fixed 元素可能被外部高层级元素遮挡。
应对策略:
- 先确认内部是否有需要与全局竞争的全屏
fixed元素,没有的话才用isolation。 - 如果有,优先使用
Teleport将需要“跳出”的元素传送到body,而不是创建局部上下文。
5. 跳出限制:Teleport 到 body
需要突破父级 overflow、transform 或局部层叠上下文时,用 Teleport 将元素挂载到 body,直接进入根层叠上下文。
el-dialog:默认append-to-body="false",留在原地;需要跳出时手动开启:append-to-body="true"。el-tooltip:默认teleported="true",已传送到body。若仍被遮挡,通常是项目中有违规的硬编码z-index,应从源头清理,而非给 Tooltip 加更大值。
总结:三条原则
- 全局层级:用
nextZIndex自动递增,禁止硬编码;通过<el-config-provider>设定基准值,并确保它包裹实际内容。 - 局部隔离:首选
Teleport移出局部上下文,慎用isolation: isolate。 - 突破限制:需要物理脱离时,用
Teleport送到body。