2019-07-07 第四周周报

CSS 中的层叠概念

在css的世界中,每个元素都有一套自己的样式规则,同时在网页中,也遵循着一套默认的排版规则,从上到下,从左到右进行排列,可是对于复杂的业务需求,默认的排版规则已经不能满足开发需求,所以我们需要去自定义元素的排列顺序,达到我们的要求,常用的属性包括position, float, display, z-index等等,同时,CSS3的到来,给网页布局带来了更多的可能性。这其中涉及到了几个重要的概念,层叠上下文、层叠水平以及层叠顺序。

1、什么是层叠上下文?

层叠上下文(stacking context)是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z轴上延伸,HTML元素依据其自身属性按照优先级顺序占用层叠上下文的空间。可以理解为,具有层叠上下文的元素,在z轴上面比普通元素更高级,离用户更近。

文档中的层叠上下文由满足以下任意一个条件的元素形成:

  • 根元素 (HTML),
  • z-index 值不为 "auto"的 绝对/相对定位,
  • 一个 z-index 值不为 "auto"的flex 项目 (flex item),即:父元素 display: flex|inline-flex,
  • opacity 属性值小于 1 的元素(参考 the specification for opacity),
  • transform 属性值不为 "none"的元素,
  • mix-blend-mode 属性值不为 "normal"的元素,
  • filter值不为“none”的元素,
  • perspective值不为“none”的元素,
  • isolation 属性被设置为 "isolate"的元素,
  • position: fixed
  • 在 will-change 中指定了任意 CSS属性,即便你没有直接指定这些属性的值(参考 这篇文章)
  • -webkit-overflow-scrolling 属性被设置 “touch”的元素

简而言之,层叠上下文分下面几类:

  1. 页面根元素天生具有层叠上下文,称之为“根层叠上下文”,也就是HTML根元素。
  2. z-index值为数值的定位元素的传统层叠上下文。
  3. 其他CSS3属性。

2、什么是层叠水平?

层叠水平(stacking level)决定了同一个层叠上下文中元素在z轴上的显示顺序,决定了层叠上下文的层叠顺序,也就是说层叠水平的讨论仅仅限于层叠上下文中,对于普通元素并无意义。层叠水平高级的要覆盖低级的,那如何确定层叠水平的高低呢?由层叠顺序决定。

3、什么是层叠顺序?

层叠顺序(stacking order)表示元素发生层叠时候有着特定的垂直显示顺序,注意,这里跟上面两个不一样,上面的层叠上下文和层叠水平是概念,而这里的层叠顺序是规则。层叠顺序基本可从下图所示中获知:


image.png

其中要注意以下几点:

  1. 位于最低水平的是层叠上下文的背景和边框。每一个层叠顺序适用于一个完整的层叠上下文,如果子元素也是一个层叠上下文,那么子元素也有一套完整自己的层叠顺序规则。
  2. 子元素的层叠上下文无法超过父元素的层叠上下文。
  3. 注意z-index: auto和z-index: 0的区别,尽管二者都表示z-index: 0的层叠水平,但是仅限于层叠水平,在层叠上下文的领域有很大差异

同时,层叠顺序遵循一下排列规则:

  1. 同一个层叠上下文领域,层叠水平大的覆盖层叠水平小的元素。
  2. 当层叠水平一致的情况下,在DOM流下面的元素覆盖上面的元素。

4、传统层叠上下文的创建

传统层叠上下文通过position属性,并配合z-index属性创建。其中z-index属性不能为默认的auto值,如果值为auto,则该元素为普通元素,其和其子元素均属于父级的层叠上下文(上图中所示第3层),现在我们先看这样的代码:

image.png
image.png

这是一个很普通的html布局,效果图如下:
image.png

可以看到红色背景的div中包含了石原里美的照片,现在让我们稍微添加一下布局属性
image.png

很容易想到,石原里美的照片被红色背景盖住了


image.png

那如何在不改变照片样式的情况下,让石原里美重回大家的视线呢?我们可以尝试修改父元素的样式:


image.png

但是我们发现,这并没有生效,那么我们把z-index改成1试试


image.png

image.png

image.png

发现z-index值小的石原里美居然又回来啦。现在我们让情况变得复杂一些,我们把父元素的样式清除,添加另一张图片,这时我们发现,图片被牢牢的压在下面,那么我们试着改变一下父元素的样式,将两个div的z-index都改成相同的样式值(如第二张图)。


image.png

image.png

我们发现z-index值更小的新垣结衣,压在了石原里美的身上,不是应该z-index值更大的在上面吗?
image.png

image.png

现在说明一下,以上两种情况的发生原因,首先是第一种情况,当我们赋予石原里美position:absolute;z-index=-1时,由于她的父元素是一个普通元素,并没有创建一个层叠上下文,因此,石原里美属于上一级的层叠上下文,也就是根元素html,那么她的父元素和她自己属于同一个层叠上下文领域(html),按照层叠顺序,z-index为负的在普通元素下面,因此红色背景覆盖在了石原里美的身上。同样的,改变父元素的z-index值为auto时,并没有使父元素含有层叠上下文。而当父元素的z-index变成具体的值1时,这个时候,就创建了一个层叠上下文,那么就相当于把石原里美从html的手中”解救“了出来,她属于父元创建的全新的层叠上下文中,按照层叠顺序,她会覆盖在父元素的background之上,重回我们面前。对于第二种情况,两张照片的父元素只有positioned属性时,均为普通元素,那么两张照片同属于根元素层叠上下文,遵循谁大谁上的原则,石原里美压在了新垣结衣的上面,当我们给父元素一个不为auto的z-index的时候,都形成了一个层叠上下文,由于两个z-index值相等,那么遵循后来居上的原则, 新垣结衣所在的div覆盖在最上面,同时,层叠上下文具有自成体系的特性,两位姑娘的比较变成了优先比较父元素的层叠顺序,因此,两位姑娘上面的z-index此时就不生效了。

需要额外注意的是,当元素具有position:fixed属性时,不管有没有z-index属性,自动创建层叠上下文。

5、CSS3其他类型层叠上下文的创建

其他类型的层叠上下文包括:

  • 一个 z-index 值不为 "auto"的flex 项目 (flex item),即:父元素 display: flex|inline-flex,
  • opacity 属性值小于 1 的元素(参考 the specification for opacity),
  • transform 属性值不为 "none"的元素,
  • mix-blend-mode 属性值不为 "normal"的元素,
  • filter值不为“none”的元素,
  • perspective值不为“none”的元素,
  • isolation 属性被设置为 "isolate"的元素,
  • position: fixed
  • 在 will-change 中指定了任意 CSS属性,即便你没有直接指定这些属性的值(参考 这篇文章)
  • -webkit-overflow-scrolling 属性被设置 “touch”的元素
  1. 父元素为display:flex或者inline-flex的情况

现在我们先给新垣结衣放个假,我们对代码做出以下调整:


image.png

注意我们给图片一个负的z-index,当我们知道,单独给元素一个z-index是不起作用的,可实际上,石原里美被红色背景牢牢遮住了,这是为什么呢,因为要满足两个条件才能形成层叠上下文:条件1是父级需要是display:flex或者display:inline-flex水平,条件2是子元素的z-index不是auto,必须是数值。此时,这个子元素为层叠上下文元素,没错,注意了,是子元素,不是flex父级元素。


image.png

也就是说,图片创建了一个层叠上下文,按照层叠顺序,z-index为负值的被盖在了普通元素红色div的下面。

  1. Opacity 与层叠上下文

直接上代码:


image.png

效果图:


image.png

我们发现z-index=-1的图片并没有被覆盖,因为当我们赋予div opacity:0.5时,便创建了一个层叠上下文,图片属于父元素的层叠上下文领域,按照层叠顺序,图片会覆盖在背景之上
  1. transform属性

代码:


image.png

效果图:


image.png

同样的,transform属性也会创建一个层叠上下文。
  1. filter属性


    image.png

    image.png

    filter属性也会创建一个层叠上下文。

其余属性,也会创建层叠上下文,大家如果感兴趣可以尝试一下

6、层叠上下文的层叠顺序

讨论了一些层叠上下文内部元素的层叠顺序和一些层叠上下文的创建方法,那么,一个层叠上下文本身处于层叠顺序中的那个层级呢?

用代码验证:


image.png

我们在两张图片中间插入一个宽度600px的绿色inline-block元素,验证他们之间的层叠顺序,效果图如下:


image.png

可以看到,本来位于第5层的inline-block元素被两个层叠上下文压在了下面。其实层叠上下文的层叠顺序被自动提升了,规则是:
  1. 一旦成为定位元素,则自动赋予z-index属性,默认值为auto,层叠等级与z-index:0相同。
  2. 而不是定位元素,则不支持z-index属性的其他层叠上下文,存在天然的z-index:auto级别,也就是说层叠等级与z-index:0的元素相同。

如果定位元素有z-index不为auto的值,那么根据谁大谁上的原则,按照z-index值进行排列。

上图中,由于新垣结衣的dom顺序在下面,因此覆盖住了石原里美,但是二者在层叠顺序表中,又比绿色背景的inline-block等级高,绿色元素被覆盖在最下面。当我们调换二者的顺序,就可证明:


image.png

image.png

以上就是关于层叠上下文和层叠等级的一些概念和使用。这样在今后页面布局的应用中,可以避免我们盲目使用z-index和定位,来达到我们想要的页面效果。

你可能感兴趣的:(2019-07-07 第四周周报)