Contents
  1. 1. 前言
  2. 2. 规则
    1. 2.1. 1. 顺序规则
    2. 2.2. 2.定位规则
    3. 2.3. 3. 参与规则
    4. 2.4. 4. 默认值规则
    5. 2.5. 5. 从父规则
    6. 2.6. 6. 层级树规则
  3. 3. 层叠上下文
    1. 3.1. 概念
    2. 3.2. 特性
    3. 3.3. 产生的条件
  4. 4. 附录:层叠的顺序表

本文介绍DOM是如何排列元素的层级顺序的,z轴方向的高低是根据什么确定的

前言

DOM层级顺序,大概来说就是DOM节点在z轴方向(垂直于屏幕向外的方向)的显示优先级。为了调整DOM层级顺序,我们想到的往往就是用CSS的z-index属性来控制。虽然看着很简单,但是有时在使用时,我们有时也许会碰到一些一些奇奇怪怪的问题:

  • 为什么有时候将z-index设成很大的值(比如9999),节点依然不能显示在最前面?
  • z-index属性设为0和不设置z-index属性有什么区别?
  • float元素和定位元素谁显示的优先级更高?

其实看似简单的层级顺序它自己的一套规则,理解这些规则可以帮助我们在开发中少踩坑。

规则

1. 顺序规则

在不设置position属性(或设置成static)的情况下,文档流后面的DOM节点会覆盖前面的DOM节点。

1
2
<div id="a">A</div>
<div id="b">B</div>

clipboard.png

PS:怎么样来让文档流中的节点叠在一起呢?比如我们可以设置DOM的margin-top为负数,这样就让两个节点叠在起一起了。不过为了简化说明,并没有把这些写出来。下同。

2.定位规则

定位节点(position属性设置为relative,absolute或fixed的节点)会覆盖非定位节点(不设置position属性或position属性设为static的节点)

1
2
<div id="a" style="position: relative">A</div>
<div id="b">B</div>

clipboard.png

根据顺序规则和定位规则, 我们可以做出更加复杂的结构。A和 B 都设为非定位节点,A 的子节点 A-1 设定定位节点。

1
2
3
4
<div id="a">
<div id="a-1" style="position: relative">A</div>
</div>
<div id="b">B</div>

clipboard.png

3. 参与规则

z-index属性仅对定位节点生效。

有三个DOM节点,其定位为static。但是A的z-index最大,但是依旧是在最底部,C的z-index最小,而在最顶部,因此可知z-index并未生效,此时为顺序规则在生效。

1
2
3
<div id="a" style="z-index: 2">A</div>
<div id="b" style="z-index: 1">B</div>
<div id="b" style="z-index: 0">B</div>

clipboard.png

我们将B和C的position设置为relative之后,顺序发生了变化。根据参与者规则和定位规则,A不是定位节点,所以即使z-index最大,还是在最底部。而根据参与规则和默认值规则(下一节介绍),B和C都是定位节点,且B的z-index要大于C,所以B在最顶部。

1
2
3
<div id="a" style="z-index: 2">A</div>
<div id="b" style="position: relative; z-index: 1">B</div>
<div id="b" style="position: relative; z-index: 0">B</div>

clipboard.png

4. 默认值规则

  • 对于所有的定位节点,z-index值大的节点会覆盖z-index值小的节点。
  • z-index设为0和没有设置z-index的节点在同一层级内没有高低之分。在IE6和7种,z-index的默认值为0,其他浏览器中默认值为auto。
1
2
3
4
<div id="a" style="position: relative; z-index: 1">A</div>
<div id="b" style="position: relative; z-index: 0">B</div>
<div id="c" style="position: relative">C</div>
<div id="d" style="position: relative; z-index: 0">D</div>

clipboard.png

5. 从父规则

两个节点A和B都是定位节点,如果节点A的z-index值比节点B的大,那么节点A的子元素都会覆盖在节点B以及节点B的子节点上。

1
2
3
4
5
6
<div id="a" style="position: relative; z-index: 1">
<div id="a-1">A-1</div>
</div>
<div id="b" style="position: relative; z-index: 0">
<div id="b-1">B-1</div>
</div>

clipboard.png

如果定位节点A和B的z-index值一样大,那么根据顺序规则,B会覆盖A,那么即使A的子节点的z-index比B的子节点大,B的子节点还是会覆盖A的子节点。(这就是为什么即使我们把A-1的z-index设置得很大,依然无法盖住B节点的原因)。

1
2
3
4
5
6
<div id="a" style="position: relative; z-index: 0">
<div id="a-1" style="position: relative; z-index: 2">A-1</div>
</div>
<div id="b" style="position: relative; z-index: 0">
<div id="b-1" style="position: relative; z-index: 1">B-1</div>
</div>

clipboard.png

6. 层级树规则

定位节点,且z-index有整数值的(不包括z-index:auto),会被放置到一个与DOM节点不一样的层级树里。

在下面的DOM节点中,A和B是兄弟节点,但是在层级树种,A和B-1才是兄弟节点(因为他们都是Root下的第一层含有整数z-index的定位节点),所以A在B和B-1之上。虽然A-1的z-index比B-1的小,但是根据从父规则,A-1也在B-1之上。

1
2
3
4
5
6
<div id="a" style="position: relative; z-index: 2">
<div id="a-1" style="position: relative; z-index: 0">A-1</div>
</div>
<div id="b">
<div id="b-1" style="position: relative; z-index: 1">B-1</div>
</div>

clipboard.png
clipboard.png

下面这个更复杂的层级树,聪明的你能看明白为什么节点层级是这样的了吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="a" style="position: relative">
<div id="a-1" style="position: relative; z-index: 100">A-1</div>
</div>
<div id="b">
<div id="b-1" style="position: relative">
<div id="b-1-1" style="position: relative; z-index: 10">B-1-1</div>
</div>
</div>
<div id="c" style="position: relative">
<div id="c-1">
<div id="c-1-1">
<div id="c-1-1-1" style="position: relative; z-index: 1">C-1-1-1</div>
</div>
</div>
</div>

clipboard.png

层叠上下文

介绍了这么多规则,是在是不好理解,又很难记。其实,要理解这些规则,我们只需要理解一个概念就行了,它就是层叠上下文。

概念

层叠上下文是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z轴上延伸,HTML元素依据其自身属性按照优先级顺序占用层叠上下文的空间。

特性

  • 子元素的 z-index 值只在父级层叠上下文中有意义。
  • 子级层叠上下文被自动视为父级层叠上下文的一个独立单元。

产生的条件

满足一下其中一个条件,即可产生一个层叠上下文:

  • 根元素 (HTML),
  • z-index 值不为 “auto”的 绝对/相对定位,
  • position: fixed
  • opacity 属性值小于 1 的元素
  • transform 属性值不为 “none”的元素
  • filter值不为“none”的元素
  • -webkit-overflow-scrolling 属性被设置 “touch”的元素

附录:层叠的顺序表

位置 描述 CSS
1(底部) 包含该层叠上下文的父元素
2 负堆叠顺序的子元素 z-index: <negative integer>; position: relative (or absolute or fixed)
3 文档流中,非内联,非定位子元素 display: /* not inline */; position: static
4 非定位浮动子元素 float: left (or right); position: static
5 内联流,非定位子元素 display: inline; position: static
6 堆叠顺序为0的子元素 z-index: auto (or 0); position: position: relative(or absolute or fixed)
7(顶部) 堆叠顺序为正的子元素 z-index: <positive integer>; position: relative(or absolute or fixed)

参考https://segmentfault.com/a/1190000014382426

Contents
  1. 1. 前言
  2. 2. 规则
    1. 2.1. 1. 顺序规则
    2. 2.2. 2.定位规则
    3. 2.3. 3. 参与规则
    4. 2.4. 4. 默认值规则
    5. 2.5. 5. 从父规则
    6. 2.6. 6. 层级树规则
  3. 3. 层叠上下文
    1. 3.1. 概念
    2. 3.2. 特性
    3. 3.3. 产生的条件
  4. 4. 附录:层叠的顺序表