层叠上下文(stacking context)
前言
关于层叠上下文这篇文章,本次当做学习记录,大部分信息来源其他文章,如果有错,感谢纠正。主要是复习记录,但例子和图片是自己画和写的。
概念
默认情况下,CSS是流式布局的,元素与元素之间不会重叠。流式布局的意思可以理解:在一个矩形的水面上,放置很多矩形的浮块,浮块会漂浮在水面上,且彼此之间依次排列,不会重叠在一起。
这是要绘制它们其实非常简单,一个个按顺序绘制即可。不过有些情况下,这种流式布局会被打破,比如使用了浮动(float)和定位(position)。因此需要需要识别出哪些脱离了正常文档流的元素,并记住它们的层叠信息,以便正确地渲染它们。那些脱离正常文档流的元素会形成一个层叠上下文,可以将层叠上下文简单理解为一个个的薄层(类似Photoshop的图层),薄层中有很多DOM元素,这些薄层叠在一起,最终形成了我们看到的多彩的页面。
层叠上下文是HTML中的一个三维概念。在css2.1的规范中,每个元素都是三维的,分别平铺在画布上的X轴,Y轴,Z轴,一般情况下,元素在页面上沿着x,y轴平铺,用户察觉不到它们在z轴上的层叠关系。一旦元元素发生层叠,这时它可能覆盖了其他元素或者被其他元素覆盖。如果一个元素含有层叠上下文,那么这个元素则为层叠上下文元素。我们可以理解为这个元素比普通元素在z轴上距离用户更近一些。
规则
- 层叠上下文的层叠水平比普通元素要高
- 层叠上下文可以嵌套,内部层叠上下文及其子元素的层叠水平受制于外部的层叠上下文;
- 层叠上下文和其兄弟元素相互独立,挤在不同的层叠上下文中,元素的层叠顺序没有可比性;
- 不同的层叠上下文元素发生层叠时,元素的层叠水平由父元素的层叠上下文的层叠顺序决定;
形成
形成层叠上下文的方法有
- 根元素
- position值为absolute【绝对定位】,relative【相对定位】,且z-index不为auto的元素
- position值为fixed【固定定位】,sticky【粘滞定位】
- z-index值不为auto的flex元素;即:父元素为display:flex||inline-flex
- grid容器的子元素,且z-index值不为auto
- opacity属性小于1的元素
- mix-blend-mode属性值不为normal的元素
- perspective/transform/filter,perspective,clip-path,mask,mask-image,mask-border,motion-path值不为none的元素
- isolation属性被设置为isolate的元素
- will-change中指定了任意css属性,即使你没有直接指定这些属性的值,该属性在 non-initial 值时会创建层叠上下文的元素
- -webkit-overflow-scrolling属性被设置touch的元素
- contain 属性值为 layout、paint 或包含它们其中之一的合成值(比如 contain: strict、contain: content)的元素。
等级
在同一层叠上下文中,定义的是该层叠上下文元素在z轴上的上下顺序。层叠等级的比较只有在同一个层叠上下文元素中才有意义,在同一个层叠上下文中,层叠等级描述定义的是该层叠上下文中的元素在Z轴上的上下顺序。
顺序
指元素遵循的规则,在同一个层叠上下文中,其中的元素遵循以下规则:
背景和边框:形成层叠上下文的背景和边框。
负z-index值:层叠上下文内有着-index值的定位子元素,负得愈大层叠等级越低;
块级盒:文档流中块级,非定位子元素;
浮动盒:非定位浮动元素;
行内盒:文档流中行内,非定位子元素;
z-index:0:z-index为0或auto的定位元素,这些元素形成了新的层叠上下文;
+z-index:z-index为正的定位元素,正的越大层叠等级越高;
对于处于同一层的元素,它们的堆叠顺序由元素在文档中出现的顺序决定。
详细的规则在w3官方文档中有描述,大家可以参考:
www.w3.org/TR/css-posi…
比较规则:
-
不同层叠上下文的元素,比较他们所在层叠上下文的层级,随所在层叠上下文整体进行排列。
-
同一个层叠上下文中,按照层叠顺序,层叠层级越高的元素越z轴上面。
-
当层叠层级和层叠顺序都相同,在DOM流中处于后面的元素会覆盖前面的元素。
-
元素层叠顺序只能够在自身所处的层叠上下文中比较 如果要与其他上下文进行比较的话 就是比较父元素。
-
如果一个元素有多个层级的元素,选择它的最高层进行比较。
- 为什么定位元素会层叠在普通元素的上面
其根本原因就在于,元素一旦成为定位元素,其z-index就会自动生效,此时其z-index就是默认的auto,也就是0级别,根据上面的层叠顺序表,就会覆盖inline或block或float元素。
而不支持z-index的层叠上下文元素天然z-index:auto级别,也就意味着,层叠上下文元素和定位元素是一个层叠顺序的,于是当他们发生层叠的时候,在DOM流中处于后面的元素会覆盖前面的元素。
举例说明
1.普通情况
<div class="box1" style="width: 100px;height: 100px;background-color: brown;">
<div class="red">box1-1</div>
<div class="green">box1-2</div>
</div>
<div class="box2" style="width: 100px;height: 100px;background-color:#f0f">
<div class="blue">box2-1</div>
<div class="blue">box2-2</div>
</div>
在这个例子中,形成的层叠上下文就只有html,box1与box2按照出现顺序排列。
2.相同层级
<div class="box1" style="width: 400px;height:100px;position: fixed;z-index:1;background-color: brown;">
</div>
<div class="box2" style="width: 50px;height:100px;position: fixed;z-index:1;background-color: rgb(190, 170, 170);">
</div>
box1与box2都会形成了新的层叠上下文,并且他们的层级相同,并且他们的都在html这一个层叠上下文中,所以层叠关系由他们代码的顺序确定,越后出现层级越高,在最上层。
2.父子元素
<div class="box1" style="width: 200px;position: absolute;z-index:-1;height: 300px;background-color: brown;">
<div style="width: 500px;height:200px;position: absolute;z-index:-10;background-color: rgb(141, 121, 121);">box1-1</div>
</div>
box1形成了一个层叠上下文,位于倒数第二层,但是box1的背景处于倒数第一层,子元素的层叠上下文z-inex为负,处于倒数第二层,子层叠上下文的层叠顺序在父层叠上下文之上。他们是父子层叠关系,不是兄弟层叠上下文,所以不能通过z-index来比较他们的层叠等级。
如果想让子元素在父元素之下,将父元素不产生层叠上下文,并且让子元素z-index为负即可。
<div class="box1" style="width: 200px;height: 300px;background-color: brown;">
<div style="width: 500px;height:200px;position: absolute;z-index:-10;background-color: rgb(141, 121, 121);">box1-1</div>
</div>
2.在相同层叠上下文的父元素内的情况
<div class="box1" style="width: 200px;position: absolute;z-index:-1;height: 300px;background-color: brown;">
<div class="box1-1" style="width: 500px;height:200px;position: absolute;z-index:9;background-color: rgb(141, 121, 121);">box1-1</div>
</div>
<div class="box2" style="width: 100px;position: absolute;height: 100px;background-color:#f0f">
<div class="box2-1" style="position: absolute;z-index:9;background-color: rgb(73, 32, 138);width:500px;">box2-2</div>
</div>
在这个例子中,box1与box2分别形成了两个层叠上下文,box1:z-index为负,box2:z-index为正;
所以box2>box1层级;而在box1子中,box1的层叠上下文的背景始终为负一层,<box1-1的z-index为负的层级;
同理 box2中box1的层叠上下文的背景始终为负一层<box2-2的z-index=9
所以就是box1<box1-1<box2<box2-2
z-index
z-index只适用于定位的元素,对非定位元素无效,它可以被设置为正整数,负整数,0,auto,如果一个定位元素没有设置z-index,那么默认为auto;元素的z-index值只在同一层叠上下文有意义。
如果父级层叠上下文的层叠等级低于另一个层叠上下文的,那么它z-index设得再高也没有用。所以如果你遇到z-index设了很大,但是不起作用的话,就去看看它的父级层叠上下文是否被其他层叠上下文盖住了。
参考:
应用: html2canvas