z-index 层叠上下文的渲染规则

最近我在 Element 里看到了一个 issue:el-image preview bug。之所以导致了这个 Bug,我觉得某种意义上来说就是因为 image 组件的 viewer(蒙版)模块开发时,没有充分理解 z-index 到底是怎么起作用的。

在此之前,我们先来看一下下面这个例子:

你可以试着变更 fixed 外部的 wrapper 对应的 CSS 样式,甚至是将它挪出来,然后看看效果。

然后你会发现,咦,fixed 尽管在视觉上确实与整个流都无关了,但是在渲染的层级上却依旧受到父级的控制,在默认情况下,它并没有上下级的关系,而是按照一定的规则渲染。

在 MDN 中有一段对于层叠上下文的总结:

层叠上下文可以包含在其他层叠上下文中,并且一起创建一个层叠上下文的层级。
每个层叠上下文都完全独立于它的兄弟元素:当处理层叠时只考虑子元素。
每个层叠上下文都是自包含的:当一个元素的内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层叠。

简单的总结一下层叠上下文的规则:

  1. 父级有 z-index 的时候,子级的 z-index 会受到父级渲染级别的限制
  2. 只有 positioned element 设置 z-index 有效(positioned index 的定义是:非 static 的 element)
  3. z-index 渲染的优先级从低到高分别是:z-index < 0 / =0 / =auto or 未设置 / z-index > 0
  4. 默认按照 DOM 树的先后顺序渲染
  5. 详细的浏览器渲染规则请见参考资料第一篇

那么我们回到 Element 的 Image 组件,看下遮罩的源代码:https://github.com/ElemeFE/element/blob/dev/packages/image/src/image-viewer.vue#L3-L4

我们会发现这里配置的 z-index 实际上是没有意义的,因为当你复合使用的时候,你无法预知父级每一层的 z-index 设置,一旦其中有一层设置了 z-index,那么这一层中设置的 z-index 将会没有任何意义。

怎么解决呢?我的建议是,但凡遮罩层,都尽量往 body 上插入,至少也需要给用户一个 body 插入的选项,这样可以很好地解决各类因为子元素创建导致的问题。

参考资料:

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 知识, 代码段, 语法

添加新评论