深入理解层叠上下文(1)

478 阅读5分钟

前言

在开始浏览本篇文章之前,请大家回答一下这个问题。

问:请问z-index:2和z-index:3哪个更高?

答:A.前者高 B.后者高 C.一样高 D.看情况

看到这个问题,如果你无法确定你的答案,或者心有疑虑,那么就请你开始阅读本篇文章,我相信看完之后你就会迎刃而解。

正文

1. z-index

了解层叠上下文之前,我们来回忆一下z-index属性。

z-index不设置的时候默认为auto,设置时只能取整数,如“1, 2, 3,-1,-2,-3,...”。

z表示垂直于屏幕的方向,也就是说z-index值越大离我们越近,反之则越远,示意图如下所示。

在使用z-index时,我们需要注意的是:

  • z-index只对指定了 position属性的元素有效
  • 当没有指定z-index的时候, 所有元素都在会被渲染在默认层(0层)
  • 当多个元素的z-index属性相同的时候(在同一个层里面),则按照正常文档流的顺序出现

下面举例说明一下:

在下一个例子中, 所有的层都是用z-index进行排序的。 元素div#5 的z-index无效, 因为他没有被指定position属性,代码请参考我的demo

2. 层叠上下文

回顾了z-index属性,我们知道某些元素的渲染顺序是由其 z-index 的值影响的。这是因为这些元素具有能够使他们形成一个层叠上下文的特殊属性,如上例中使用了的position属性。

那到底什么是层叠上下文呢,MDN文档中给出的解释是:我们假定用户正面向(浏览器)视窗或网页,而 HTML 元素沿着其相对于用户的一条虚构的 z 轴排开,层叠上下文就是对这些 HTML 元素的一个三维构想。众 HTML 元素基于其元素属性按照优先级顺序占据这个空间。

嗯,是不是有点绕。没关系,下面我给大家举个例子解释一下。 有这么一个html结构:

各div的z-index属性和position属性按照上图所示设置,我们得到如下结果:

我们可以看到DIV #4在DIV #2的上面,没有问题,因为DIV #4的z-index较大。 现在,我们做一些改变,我们将DIV #3的position改为absolute,改变后的html结构如下:

我们得到这样一个结果。
可以看到,现在DIV #2 (z-index: 2)在DIV #3 (z-index: 1)的上面,因为他们都属于同一个层叠上下文(根元素创建的层叠上下文),所以z-index的值决定了元素如何叠放。

但是,奇怪的是DIV #2 (z-index: 2)在DIV #4 (z-index: 10)的上面,尽管DIV #2的z-index值小于DIV #4。这是因为,它们不属于同一个层叠上下文。DIV #4处于DIV #3所创建的层叠上下文中,而整个DIV #3(包含其后代元素)是在DIV #2下面的。

简单来说就是,假如说每个层叠上下文就是一个小世界,每个小世界的z-index就和外界无关,只有处于同一个小世界的z-index才可以比较。

- 分析

第一个例子中,虽然DIV #1和DIV #3均设为相对定位,但是没有设置z-index的值。这里补充一个知识点,z-index不设置时默认为auto,且z-index:0和z-index:auto是完全不一样的

所以,DIV #1,DIV #2,DIV #3,DIV #4均处于同一个世界,即根节点html创造的层叠上下文。

而第二个例子中,由于DIV #3设置了z-index:1,这就使DIV #4只存在于DIV #3创造的层叠上下文中,由于DIV #3的z-index小于DIV #2的z-index,所以DIV #2在最上面。示意图如下所示:

具体代码请参考我的demo

- 补充

现在我们理解了什么是层叠上下文,通过上例我们也知道只有部分元素可以创造层叠上下文,那么具体有哪些呢,我们可以参考MDN的文档,里面给出了相关元素,这里只给大家列举几个重要的元素:

  • 文档根元素(<html>);
  • position 值为 absolute(绝对定位)或  relative(相对定位)且 z-index 值不为 auto 的元素;
  • position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);
  • flex (flexbox) 容器的子元素,且 z-index 值不为 auto
  • grid (grid) 容器的子元素,且 z-index 值不为 auto
  • opacity 属性值小于 1 的元素;

小结

通过上面两个例子我们得到如下结论:

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

那么如果涉及到浮动元素,div又是如何分层的呢,请继续看我的另一篇文章深入理解层叠上下文(2).

由于本人水平有限,如有描述不准确的地方请给我留言,欢迎交流~

本文为个人原创,转载请注明出处。