2015/09/02 · CSS · 层叠上下文
原文出处: elcarim的博客
在CSS2.1规范中,每个盒模型的位置是三维的,分别是平面画布上的x轴,y轴以及表示层叠的z轴。对于每个html元素,都可以通过设置z-index
属性来设置该元素在视觉渲染模型中的层叠顺序。
z-index
可以设置成三个值:
auto
,默认值。当设置为auto
的时候,当前元素的层叠级数是0,同时这个盒不会创建新的层级上下文(除非是根元素,即<html>
);<integer>
。指示层叠级数,可以使负值,同时无论是什么值,都会创建一个新的层叠上下文;inherit
。除了由根根元素创建的根层叠上下文以外,其它上下文是由z-index
不为auto
的“positioned”元素所创建。
参考层叠级数,浏览器会根据以下规则来渲染绘制每个在同一个层叠上下文中的盒模型:
(从先绘制到后绘制)
z-index
为负值的子元素,数值越小越早被绘制;在规则中,提到了几种元素的修饰词,下面是简单的解释:
position
为fixed
,absolute
,relative
;那么如果未设置或为static
的就是“non-positioned”元素;fixed
、absolute
)的元素,又或者是根元素;如果不是上述情况,那个这个元素就是“in-flow”;display
为inline
,inline-table
,inline-block
的元素;规则有点多,但简单说,就是父元素会先绘制,接着是z-index
为负值的子元素,然后是“non-positioned”元素,最后是按照层叠级数从0开始逐级绘制(这样说比较简单,省略了大量细节,因此并不是很准确)。如果层级相同,则按照元素在DOM树中的顺序来进行绘制。
从这样看,要让z-index
非负的元素按照层级控制生效,那么就将该元素设置为“positioned”,这也是许多文章中普遍提到的规则。
下面,将利用MDN中的例子来分析和解释层叠上下文中的规则和计算方法,部分代码使用的MDN上的源码,另外一些是经过细微修改,目的是为了更好得把问题描述得更清楚。
2015/10/09 · CSS · 层叠上下文
原文出处: HaoyCn
前言:关于层叠上下文,笔者还没有去阅读更详细的 W3C 规范来了解更本质的原理(表打我,等我校招拿到 offer 了我就读好伐 T_T)。一直听说 CSS3 里的层叠上下文有新情况,但没找到很好的参考资料,故自己实战一把。鉴于笔者水平有限,如有任何遗漏或者错误,则恳请读者斧正。
2016/04/30 · CSS · z-index
原文出处: 北风吹雪
z-index在日常开发中算是一个比较常用的样式,一般理解就是设置标签在z轴先后顺序,z-index值大的显示在最前面,小的则会被遮挡,是的,z-index的实际作用就是这样。
但是你真的了解z-index吗?你知道它有什么特性吗?这里先抛出几个名词:“层叠顺序(stacking order)”,“层叠上下文(stacking context)”,“层叠水平(stacking level)”。
先说一下z-index的基本用法:
z-index
可以设置成三个值:
auto
,默认值。当设置为auto
的时候,当前元素的层叠级数是0,同时这个盒不会创建新的层级上下文(除非是根元素,即<html>
);<integer>
。指示层叠级数,可以使负值,同时无论是什么值,都会创建一个新的层叠上下文;inherit
。父元素继承z-index只在定位元素中起作用,举栗子:
XHTML
<style> #box1{ background: blue; width: 200px; height: 200px; } #box2{ background: yellow; width: 200px; height: 200px; margin-top:-100px; } </style> <div id="box1"></div> <div id="box2"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<style>
#box1{
background: blue;
width: 200px;
height: 200px;
}
#box2{
background: yellow;
width: 200px;
height: 200px;
margin-top:-100px;
}
</style>
<div id="box1"></div>
<div id="box2"></div>
|
我们希望box1要显示在box2上面,可能这时候有同学会说,给box1加一个z-index大于0的值就可以了,这样是不对的,如图:
box2遮挡了box1,即使box1设置z-index值再大也白搭,前面说了z-index只在定位元素(position=static除外,因为元素默认就是static,相当于没用position样式)中作用,也是就z-index要配合position一起使用。感兴趣的可以亲自验证一下,这里只抛砖引玉。
层叠顺序对绝对元素的Z轴顺序
层叠顺序其实不是z-index独有的,每个元素都有层叠顺序,元素渲染的先后顺序跟它有很大关系,总之当元素发生层叠时,元素的层级高的会优先显示在上面,层级一样的则会根据dom的先后顺序进行渲染,后面的会覆盖前面的。文字再多可能也没有一张图来的直接,下面这张图是“七阶层叠水平”(网上盗的,很经典的一张图)
再举个栗子,这里还是拿刚才那个栗子来说,在不用z-index的前提下,利用css层叠顺序解决遮挡问题,代码修改如下
CSS
<style> #box1{ background: blue; width: 200px; height: 200px; display:inline-block; } #box2{ background: yellow; width: 200px; height: 200px; margin-top:-100px; } </style> <div id="box1"></div> <div id="box2"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<style>
#box1{
background: blue;
width: 200px;
height: 200px;
display:inline-block;
}
#box2{
background: yellow;
width: 200px;
height: 200px;
margin-top:-100px;
}
</style>
<div id="box1"></div>
<div id="box2"></div>
|
这里只做了细微的修改,就是给box1加了一个display:inline-block;的样式,这里解释一下,首先box1和box2发生了层叠,然后box默认为块级元素,即display:block,从七阶图中看出,display:block的元素的层叠水平低于display:inline-block的元素,所以浏览器就将box2渲染到box1上面,如图:
灵活的运用七阶图可以让你的代码尽可能的减少z-index的使用。因为多个人开发同一个系统,如果过多的用z-index,很有可能会出现冲突,即遮挡问题,一般来说z-index使用10以内的数值就足够了。
重点:层叠上下文
先说一下如果创建层叠上下文,css创建层叠上下文的方法有很多,但是常用的也就够那么几种
1、定位元素中z-index不等于auto的会为该元素创建层叠上下文
2、html根元素默认会创建层叠上下文(这是一个特例,知道就行)
3、元素的opacity不等于1会创建层叠上下文
4、元素的transform不等于none会创建层叠上下文
还有其它方式创建层叠上下文,这里就不做介绍了,上面四中是开发中常用到的。
那么知道怎么创建层叠上下文之后,问题的关键来了,层叠上下文有什么用呢?
这里一定要结合前面那张七阶图,最下面那一层background便是是建立在层叠上下文的基础上的,也就是说在层叠上下文中,所有的元素都会渲染在该元素的层叠上下文背景和边框上面;在block盒子、float盒子等不存在层级上下文的元素中,子元素设置z-index为负值的时候,**那么子元素会被父元素遮挡**。说了可能不太好理解,举个栗子消化一下:
XHTML
<style> #box1{ position: relative; width: 200px; height: 200px; background: blue; } #box2{ position: relative; z-index:-1; width: 100px; height: 100px; background: yellow; } </style> <div id="box1"> <div id="box2"></div> </div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<style>
#box1{
position: relative;
width: 200px;
height: 200px;
background: blue;
}
#box2{
position: relative;
z-index:-1;
width: 100px;
height: 100px;
background: yellow;
}
</style>
<div id="box1">
<div id="box2"></div>
</div>
|
里,box并没有创建层叠上下文,当子元素box2设置z-index:-1时,box2所在的层叠上下文是根元素,即html根标签,根据七阶图可以看出,box2会渲染在html标签上面,普通盒子box1(z-index:auto)下面,所以box2被遮挡了。如图所示:
那么怎么解决这个问题呢?相信大家已经知道这里该怎么处理了吧,是的,为box1建立一个层叠上下文,那么box1中的元素无论z-index是负的多少,都会显示在box1的背景之上,如图:
这里我用了前面说的的第一种方式去创建层叠上下文,即定位元素中z-index不为auto的元素会建立层叠上下文,可能有的同学开始纳闷了,box1的z-index小于box2的z-index,为什么box2缺显示在box1的上面呢?呵呵,这正对应了七阶图的层叠水平的关系,不明白的再仔细揣摩一下七阶图。
· 层叠水平仅在直接父级层叠上下文中进行比较,即层叠上下文A中的子元素的层叠水平不会和另一个层叠上下文中的子元素进行比较。举个例子
XHTML
<style> #box1{ z-index: 10; position: relative; width: 200px; height: 200px; background: green; } #box1_1{ position: relative; z-index: 100; width: 100px; height: 100px; background: blue; } #box2{ position: relative; z-index: 11; width: 200px; height: 200px; background: red; margin-top: -150px; } </style> <div id="box1"> <div id="box1_1"> </div> </div> <div id="box2"> </div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<style>
#box1{
z-index: 10;
position: relative;
width: 200px;
height: 200px;
background: green;
}
#box1_1{
position: relative;
z-index: 100;
width: 100px;
height: 100px;
background: blue;
}
#box2{
position: relative;
z-index: 11;
width: 200px;
height: 200px;
background: red;
margin-top: -150px;
}
</style>
<div id="box1">
<div id="box1_1">
</div>
</div>
<div id="box2">
</div>
|
叠上下文box1中的子元素box2设置z-index为100,而层叠上下文box2的z-index只有11,而实际的渲染效果却是,box2在box1和box1_1的上面,这就应了上面那就话,层叠水平仅在元素的第一个父级层叠上下文中进行,即层叠上下文A中的子元素的层叠水平不会和另一个层叠上下文中的子元素进行比较,也就是活box1_1的z-index对于他的父级层叠上下文之外的元素没有任何影响。这里box2和box1在同一个层叠上下文中(html根元素会默认创建层叠上下文),所以它们两个会进行层叠水平的比较,box2的z-index大于box1的z-index,所以我们看到的也就是下面这样,box2遮挡了box1,不在乎box1中的子元素z-index是多少,如图:
这里我对z-index的理解也就讲述完毕了,大概就说了以下这几点内容:
1、z-index仅在定位元素(position不等于static)中有效
2、七阶层叠水平图
3、z-index层叠水平的比较仅限于父级层叠上下文中
其次需要注意以下几点:
1、在开发中尽量避免层叠上下文的多层嵌套,因为层叠上下文嵌套过多的话容易产生混乱,如果对层叠上下文理解不够的话是不好把控的。
2、非浮层元素(对话框等)尽量不要用z-index(通过层叠顺序或者dom顺序或者通过层叠上下文进行处理)
3、z-index设置数值时尽量用个位数
用了一晚上的时间整理了这篇文章,就连我自己对z-index也有了更加深刻的理解,希望对你也有帮助。如有错误 欢迎指正
2 赞 6 收藏 评论
利用MDN上的一个例子来说明。
为了方便比较,将源码简化成如下:
XHTML
<body> <div id="absdiv1">DIV #1</div> <div id="reldiv1">DIV #2</div> <div id="reldiv2">DIV #3</div> <div id="absdiv2">DIV #4</div> <div id="normdiv">DIV #5</div> </body>
1
2
3
4
5
6
7
|
<body>
<div id="absdiv1">DIV #1</div>
<div id="reldiv1">DIV #2</div>
<div id="reldiv2">DIV #3</div>
<div id="absdiv2">DIV #4</div>
<div id="normdiv">DIV #5</div>
</body>
|
其中DIV#1
和DIV#4
是粉色框,position
设置为absolute
;
DIV#2
和DIV#3
是粉色框,position
设置为relative
;
DIV#5
是黄色框,position
为设置,默认static
;
根据规则,由于DIV#5
是“non-positioned”,即使DIV#5
是DOM树中最后的元素,它也是最早被绘制的,因此它处于所有“positioned”的下面;而对于其余四个“positioned”的DIV
,它们的绘制顺序就是按照在DOM树中的顺序绘制,即DIV#1
->DIV#2
->DIV#3
->DIV#4
。
尽管DIV#5
是最“先绘制”的,但是浏览器在解析HTML的时候仍然是按照HTML文档流的顺序来解析的,实际的绘制顺序仍然是DIV#1
->DIV#2
->DIV#3
->DIV#4
->DIV#5
。只不过,要绘DIV#5
的时候,会对影响到的元素进行重新绘制,其渲染的效果看上去的顺序是DIV#5
->DIV#1
->DIV#2
->DIV#3
->DIV#4
,将DIV#5
提到了最前。
z-index用来控制元素重叠时堆叠顺序。
适用于:已经定位的元素(即position:relative/absolute/fixed)。
一般理解就是数值越高越靠上,好像很简单,但是当z-index应用于复杂的HTML元素层次结构,其行为可能很难理解甚至不可预测。因为z-index的堆叠规则很复杂,下面一一道来。
首先解释一个名词:
stacking context:翻译就是“堆叠上下文”。每个元素仅属于一个堆叠上下文,元素的z-index描述元素在相同堆叠上下文中“z轴”的呈现顺序。
z-index取值:
默认值auto:
当页面新生成一个box时,它默认的z-index值为auto,意味着该box不会自己产生一个新的local stacking context,而是处于和父box相同的堆叠上下文中。
正/负整数
这个整数就是当前box的z-index值。z-index值为0也会生成一个local stacking context,这样该box父box的z-index就不会和其子box做比较,相当于隔离了父box的z-index和子box的z-index。
接下来从最简单的不使用z-index的情况开始将,循序渐进。
Background and borders — of the element forming the stacking context. The lowest level in the stack.
Negative Z-Index — the stacking contexts of descendants elements with negative z-index.
Block Level Boxes — in-flow non-inline-level non-positioned descendants.
Floated Boxes — non-positioned floats
Inline Boxes — in-flow inline-level non-positioned descendants.
Z-index: 0 — positioned elements. These form new stacking contexts.
Positive Z-index — positioned elements. The highest level in the stack.
图文来源:http://webdesign.tutsplus.com/articles/what-you-may-not-know-about-the-z-index-property–webdesign-16892
现在该笔者上场翻译了!在解释上面术语之前,需要阐明两个术语:“定位”指的是 position
为 relative
、absolute
、fixed
的元素,“非定位”则相反。
z-index
为负的后代元素建立的层叠上下文position: relative
的浮动盒)z-index
为正的)定位元素。层叠的最高等级引文如上所表。但笔者提醒各位读者一点,“Z-index: 0”级的定位元素不一定就会建立新的层叠上下文。因为:
CSS2.1:(z-index: auto)The stack level of the generated box in the current stacking context is 0. The box does not establish a new stacking context unless it is the root element.
当定位元素 z-index: auto
,生成盒在当前层叠上下文中的层级为
0。但该盒不建立新的层叠上下文,除非是根元素。
规范是这样,但 IE6-7 有个
BUG,定位元素即便 z-index: auto
照样创建层叠上下文。
以上是基于 CSS2.1 的层叠上下文介绍。下面要阐述的是在 CSS3 新环境下,层叠上下文的新变化。
同样是要MDN上面的例子来说明。
JavaScript
<body> <div id="absdiv1"> <br /><span class="bold">DIV #1</span> <br />position: absolute; </div> <div id="flodiv1"> <br /><span class="bold">DIV #2</span> <br />float: left; </div> <div id="flodiv2"> <br /><span class="bold">DIV #3</span> <br />float: right; </div> <br /> <div id="normdiv"> <br /><span class="bold">DIV #4</span> <br />no positioning </div> <div id="absdiv2"> <br /><span class="bold">DIV #5</span> <br />position: absolute; </div> </body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<body>
<div id="absdiv1">
<br /><span class="bold">DIV #1</span>
<br />position: absolute;
</div>
<div id="flodiv1">
<br /><span class="bold">DIV #2</span>
<br />float: left;
</div>
<div id="flodiv2">
<br /><span class="bold">DIV #3</span>
<br />float: right;
</div>
<br />
<div id="normdiv">
<br /><span class="bold">DIV #4</span>
<br />no positioning
</div>
<div id="absdiv2">
<br /><span class="bold">DIV #5</span>
<br />position: absolute;
</div>
</body>
|
其中DIV#1
和DIV#5
是粉色框,position
设置为absolute
;
DIV#1
和DIV#2
是粉色框,float
设置分别为left
和right
,opacity
是1;
DIV#4
是黄色框,position
为设置,默认static
;
上一节的例子类似,由于DIV#4
是“non-positioned”,所以DIV#4
仍然是最先绘制的,因此它的背景和边界将在所有元素的最下面。而且根据规则,DIV#4
中的inline-level元素()会在浮动元素绘制以后才绘制,结果是
被挤到了DIV#2
的右边。
根据规则,浮动元素是在“positioned”元素之前绘制,因此DIV#1
和DIV#5
会在两个浮动元素的上面。
要注意到,在这里几个<div>
的并没有设置透明度,这跟MDN上的源码有所区别。那现在,如果完全按照MDN的源码,将DIV#1
,DIV#2
,DIV#3
,DIV#5
的opacity
设置为0.7
,显示结果如下:
仔细观察,可以发现,在设置了opacity
后,DIV#3
的层级被提高到了DIV#1
之上了。这与CSS2.1上的规定有所区别。
如果对DIV#4
设置opacity:0.99
,结果更加出人意料:
原本在最下面的DIV#4
跑到了更加前面的位置,只位于DIV#5
之下。
由于opacity
并不是在CSS2.1里规定,需要使用CSS3中新的规则来解释这一个现象,更容易理解z-index的规则,现在暂时不讨论opacity
所带来的影响,避免把规则变得更复杂。
不使用z-index的情况,也是默认的情况,即所有元素都不用z-index时,堆叠顺序如下(从下到上)
解释一下后两条规则:
例子:
<!DOCTYPE
html> <html> <head> <meta charset="UTF-8">
<title>Stacking without z-index</title> <style
type="text/css"> div { font: 12px Arial; text-align: center; } .bold
{ font-weight: bold; } .opacity{opacity: 0.7;} #normdiv { height: 70px;
border: 1px dashed #999966; background-color: #ffffcc; margin: 0px
50px 0px 50px; } #reldiv1 { height: 100px; position: relative; top:
30px; border: 1px dashed #669966; background-color: #ccffcc; margin:
0px 50px 0px 50px; } #reldiv2 { height: 100px; position: relative; top:
15px; left: 20px; border: 1px dashed #669966; background-color:
#ccffcc; margin: 0px 50px 0px 50px; } #absdiv1 { position: absolute;
width: 150px; height: 350px; top: 10px; left: 10px; border: 1px dashed
#990000; background-color: #ffdddd; } #absdiv2 { position: absolute;
width: 150px; height: 350px; top: 10px; right: 10px; border: 1px dashed
#990000; background-color: #ffdddd; } </style> </head>
<body> <br /><br /> <div id="absdiv1"
class="opacity"> <br /><span class="bold">DIV
#1</span> <br />position: absolute; </div> <div
id="reldiv1" class="opacity"> <br /><span
class="bold">DIV #2</span> <br />position: relative;
</div> <div id="reldiv2" class="opacity"> <br
/><span class="bold">DIV #3</span> <br />position:
relative; </div> <div id="absdiv2" class="opacity"> <br
/><span class="bold">DIV #4</span> <br />position:
absolute; </div> <div id="normdiv"> <br /><span
class="bold">DIV #5</span> <br />no positioning
</div> </body> </html> View Code
有图有真相:
分析:
#5没有定位,处于正常流,所以根据以上规则,先于#1,#2,#3,#4这些已定位元素渲染,在最下方。
#1,#2,#3,#4都是已定位元素,且未设置z-index,所以根据其在文档中出现的顺序依次被渲染,可以去掉apacity查看清晰效果。
总的来说变化可以归为两点,我们之后一一探讨:
tranform
属性改变绝对定位子元素的包含块再次使用MDN中的例子:
XHTML
<body> <div id="absdiv1">DIV #1</div> <div id="reldiv1">DIV #2</div> <div id="reldiv2">DIV #3</div> <div id="absdiv2">DIV #4</div> <div id="normdiv">DIV #5</div> </div>
1
2
3
4
5
6
7
|
<body>
<div id="absdiv1">DIV #1</div>
<div id="reldiv1">DIV #2</div>
<div id="reldiv2">DIV #3</div>
<div id="absdiv2">DIV #4</div>
<div id="normdiv">DIV #5</div>
</div>
|
为了让结构更加清楚,简化了HTML源码,下面是每个<div>
的属性设置:
DIV#1
:position: absolute
,z-index: 5
;DIV#2
:position: relative
,z-index: 3
;DIV#3
:position: relative
,z-index: 2
;DIV#4
:position: absolute
,z-index: 1
;DIV#5
:position: static
,z-index: 8
;又见到了可怜的DIV#5
,尽管它的z-index:8
是所有元素中最大的,但由于它是“non-posititoned”所以,它在层叠上还是地位低下,仍然要老老实实呆在其他元素的下面。
而对于其他“positioned”元素,它们的绘制顺序就是按照z-index的大小来加以分别,因此尽管DIV#1
在DOM树中是最靠前的,但由于它的z-index: 5
比其他都大,因此就成了最顶层的元素了。
首先,回忆一下,创造层叠上下文的两种情况:
z-index
不为auto
的positioned
元素;### 实例一(同一层叠上下文中的时代)
继续使用MDN上的例子,来说明如果层叠上下文对z-index
计算的影响。
XHTML
<body> <div id="div1"> <div id="div2"></div>
</div> <div id="div3"> <div id="div4"></div>
</div> </body>
<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6938563cb085489625-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6938563cb085489625-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6938563cb085489625-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6938563cb085489625-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6938563cb085489625-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6938563cb085489625-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f6938563cb085489625-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6938563cb085489625-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f6938563cb085489625-9">
9
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6938563cb085489625-1" class="crayon-line">
<body>
</div>
<div id="crayon-5b8f6938563cb085489625-2" class="crayon-line crayon-striped-line">
<div id="div1">
</div>
<div id="crayon-5b8f6938563cb085489625-3" class="crayon-line">
<div id="div2"></div>
</div>
<div id="crayon-5b8f6938563cb085489625-4" class="crayon-line crayon-striped-line">
</div>
</div>
<div id="crayon-5b8f6938563cb085489625-5" class="crayon-line">
</div>
<div id="crayon-5b8f6938563cb085489625-6" class="crayon-line crayon-striped-line">
<div id="div3">
</div>
<div id="crayon-5b8f6938563cb085489625-7" class="crayon-line">
<div id="div4"></div>
</div>
<div id="crayon-5b8f6938563cb085489625-8" class="crayon-line crayon-striped-line">
</div>
</div>
<div id="crayon-5b8f6938563cb085489625-9" class="crayon-line">
</body>
</div>
</div></td>
</tr>
</tbody>
</table>
免去其他杂乱的样式和显示,HTML的主体结构如上所示,其中的属性设置如下:
- `DIV#1`:`position: relative`;
- `DIV#2`:`position: absolute`, `z-index: 1`;
- `DIV#3`:`position: relative`;
- `DIV#4`:`posititon: absolute`;
从代码就可以推断出,除了根元素创建的根层叠上下文以外,还有`DIV#2`所创建的层叠上下文。因此,尽管`DIV#2`与`DIV#3`或`DIV#4`都不在一个BFC(块格式化上下文)中,但它们都同处于一个层叠上下文中,因此根据层叠规则,`DIV#2`的`z-index`最高,因此处于另外三个元素之上。
显示的结果则如下图:
当然,如果将DIV#4
设置z-index: 2
,那么DIV#4
就会跑到最顶部:
从此可以得知,层叠计算时,将考虑同一个层叠上下文中的所有元素而不考虑元素是否有其他联系。
浮动元素z-index位置介于非定位元素和定位元素之间。(从下到上)
non-positioned元素的背景和边界没有被浮动元素影响,但是元素中的内容受影响(浮动布局特性)
举例:
<!DOCTYPE
html> <html> <head> <meta charset="UTF-8">
<title>Stacking and float</title> <style
type="text/css"> div { font: 12px Arial; text-align: center; } .bold
{ font-weight: bold; } .opacity{ opacity: 0.7;} #absdiv1 { position:
absolute; width: 150px; height: 200px; top: 10px; right: 140px; border:
1px dashed #990000; background-color: #ffdddd; } #normdiv { /*
opacity: 0.7; */ height: 100px; border: 1px dashed #999966;
background-color: #ffffcc; margin: 0px 10px 0px 10px; text-align: left;
} #flodiv1 { margin: 0px 10px 0px 20px; float: left; width: 150px;
height: 200px; border: 1px dashed #009900; background-color: #ccffcc;
} #flodiv2 { margin: 0px 20px 0px 10px; float: right; width: 150px;
height: 200px; border: 1px dashed #009900; background-color: #ccffcc;
} #absdiv2 { position: absolute; width: 150px; height: 100px; top:
130px; left: 100px; border: 1px dashed #990000; background-color:
#ffdddd; } </style> </head> <body> <br /><br
/> <div id="absdiv1" class="opacity"> <br /><span
class="bold">DIV #1</span> <br />position: absolute;
</div> <div id="flodiv1" class="opacity"> <br
/><span class="bold">DIV #2</span> <br />float:
left; </div> <div id="flodiv2" class="opacity"> <br
/><span class="bold">DIV #3</span> <br />float:
right; </div> <br /> <div id="normdiv"> <br
/><span class="bold">DIV #4</span> <br />no
positioning </div> <div id="absdiv2" class="opacity"> <br
/><span class="bold">DIV #5</span> <br />position:
absolute; </div> </body> </html> View Code
分析:
#4是正常流中非定位的元素,所以先被渲染,在最底层。
#2 #3一个左浮动,一个右浮动,接着被渲染。彼此不会因为z-index值被覆盖。见下图。
#1 #5为已定位的元素,最后被渲染,当浏览器窗口变小时,#5在#1上面,因为HTML文档中#5在#1后面。见下图。
以下情况会产生新的层叠上下文:
z-index
值不为 auto
Flex Item
,且 z-index
值不为 auto
,即父元素 display: flex|inline-flex
opacity
属性值小于 1transform
属性值不为 none
mix-blend-mode
属性值不为 normal
filter
属性值不为 normal
isolation
属性值为 isolate
position: fixed
will-change
中指定了上述任意属性,即便你没有直接定义这些属性-webkit-overflow-scrolling
属性值为 touch
以上列表译自:
,提醒广大读者,别看中文版,因为中文版并非实时跟进更新的,且翻译不太准确
依然上上面的例子:
XHTML
<body> <div id="div1"> <div id="div2"></div> </div> <div id="div3"> <div id="div4"></div> </div> </body>
1
2
3
4
5
6
7
8
9
|
<body>
<div id="div1">
<div id="div2"></div>
</div>
<div id="div3">
<div id="div4"></div>
</div>
</body>
|
但现在将各个元素的属性做一些修改:
DIV#1
:position: relative
;DIV#2
:position: absolute
, z-index: 2
;DIV#3
:position: relative
,z-index: 1
;DIV#4
:posititon: absolute
,z-index: 100
;在看结果之前,先根据源码推断一下计算的结果。首先,DIV#2
创建了一个层叠上下文(SC2),而DIV#2
本身在根层叠上下文中的层级是2;与DIV#2
处于同一个层叠上下文的DIV#3
也创建了一个层叠上下文(SC3),同时由于其z-index
是1
,比DIV#2
要小,DIV#3
理所当然地会屈于DIV#2
之下;另外,DIV#3
还有一个子元素DIV#4
,DIV#4
显然是处于DIV#3
所创建的层叠上下文(SC3)中,同时,自己又创建了另一个新的层级上下文(SC4)。
那么问题来了,DIV#4
的z-index
是100
,比所有元素都要大,那么DIV#4
会处于什么位置呢?
从结果可以看到,DIV#2
和DIV#3
位置和预想中是一样的,但由于DIV#4
则是处于DIV#2
之下DIV#3
之上。其中原因还,DIV#4
所处的层叠上下文SC3的层级比SC2要低,因此不管DIV#4
有多大,它都不会超过比自身高的层叠上下文中的元素。
如果改一改各个元素的属性:
DIV#1
:position: relative
,z-index: 1
;DIV#2
:position: absolute
, z-index: 100
;DIV#3
:position: relative
,z-index: 1
;DIV#4
:posititon: absolute
,z-index: 2
;通过修改代码,我们让DIV#1
和DIV#3
的z-index
为1
,它们在SC0(根层叠上下文)中的层级都是1,那么它们将按照DOM树的顺序来绘制,这意味着DIV#3
稍微比DIV#1
高那么一点。
在这两个层叠上下文中,分别有子元素DIV#2
和DIV#4
。此时,尽管DIV#2
的层级数非常大,但由于它所处的层叠上下文SC1在SC3之下,因此DIV#2
不仅在DIV#4
之下,还会位于DIV#3
之下。显示结果如下图所示:
通过这个例子,可以更清楚得认识到,层叠的计算是非常依赖所处的层叠上下文的,用刚通俗的话讲,层叠计算时期是一个拼爹的时代。
默认的堆叠顺序上面说了,要想改变 元素的堆叠顺序就得用到z-index。
Note:前两种情况中,虽然有元素之间的重叠覆盖,但是它们都是处在同一个z-layer的。因为没有设置z-index属性,默认的渲染层就是layer 0。所以要注意,不同层中元素之间覆盖是理所当然的,但是同一层中的元素也会发送覆盖。
z-index只适用于已经定位的元素(即position:relative/absolute/fixed)。
举例:
<!DOCTYPE
html> <html> <head> <meta charset="UTF-8">
<title>Stacking without z-index</title> <style
type="text/css"> div { font: 12px Arial; text-align: center; opacity:
0.7; } .bold { font-weight: bold; } #normdiv { z-index: 8; height:
70px; border: 1px dashed #999966; background-color: #ffffcc; margin:
0px 50px 0px 50px; } #reldiv1 { z-index: 3; height: 100px; position:
relative; top: 30px; border: 1px dashed #669966; background-color:
#ccffcc; margin: 0px 50px 0px 50px; } #reldiv2 { z-index: 2; height:
100px; position: relative; top: 15px; left: 20px; border: 1px dashed
#669966; background-color: #ccffcc; margin: 0px 50px 0px 50px; }
#absdiv1 { z-index: 5; position: absolute; width: 150px; height: 350px;
top: 10px; left: 10px; border: 1px dashed #990000; background-color:
#ffdddd; } #absdiv2 { z-index: 1; position: absolute; width: 150px;
height: 350px; top: 10px; right: 10px; border: 1px dashed #990000;
background-color: #ffdddd; } </style> </head> <body>
<br /><br /> <div id="absdiv1"> <br /><span
class="bold">DIV #1</span> <br />position: absolute;
<br />z-index: 5; </div> <div id="reldiv1"> <br
/><span class="bold">DIV #2</span> <br />position:
relative; <br />z-index: 3; </div> <div id="reldiv2">
<br /><span class="bold">DIV #3</span> <br
/>position: relative; <br />z-index: 2; </div> <div
id="absdiv2"> <br /><span class="bold">DIV
#4</span> <br />position: absolute; <br />z-index: 1;
</div> <div id="normdiv"> <br /><span
class="bold">DIV #5</span> <br />no positioning <br
/>z-index: 8; </div> </body> </html> View Code
以上元素建立新层叠上下文的同时,也会提升元素自身所在层叠上下文中的层级。
我们以 opacity
为例。来看下 CSS3 规范中的话:
If an element with opacity less than 1 is not positioned, implementations must paint the layer it creates, within its parent stacking context, at the same stacking order that would be used if it were a positioned element with ‘z-index: 0’ and ‘opacity: 1’. If an element with opacity less than 1 is positioned, the ‘z-index’ property applies as described in [CSS21], except that ‘auto’ is treated as ‘0’ since a new stacking context is always created.
如果元素 opacity
小于 1
且未定位,则必须在其父层叠上下文中,按其在定位了的、z-index: 0
且 opacity: 1
的情况中的层叠顺序绘制。如果 opacity
小于
1 且已定位,z-index
属性按 CSS2.1
应用,但 auto
要视为 0
,因为新的层叠上下文总是创建了的。
如下案例:
CSS
div { width: 100px; height: 100px; } #box1 { position: absolute; background: red; top: 40px; left: 40px; } #box2 { background: blue; } <body> <div id="box1"></div> <div id="box2"></div> <body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
div {
width: 100px;
height: 100px;
}
#box1 {
position: absolute;
background: red;
top: 40px;
left: 40px;
}
#box2 {
background: blue;
}
<body>
<div id="box1"></div>
<div id="box2"></div>
<body>
|
以上 CSS 和 HTML 片段中,由于 box1 是绝对定位(层级为“Z-index: 0”级),而 box2 是文档流内块级盒(层级为“块级盒”级),因此 box1 会层叠在 box2 之上。下面添加如下 CSS 规则:
CSS
#box2 { opacity: .5; }
1
2
3
|
#box2 {
opacity: .5;
}
|
这时候, box2 则会层叠在 box1 之上了。因为 box2 的 opacity
为
0.5(小于 1),故视其为“Z-index: 0”级,也就和 box1
同级了。同级情况下,按照二者在源代码中的顺序,居后的 box2
又重新占领高地了。
读者可以取下面规则之任意一条实验,都能达到同样效果:
CSS
#box2 { transform: scale(1); mix-blend-mode: difference; isolation: isolate; -webkit-filter: blur(5px); }
1
2
3
4
5
6
|
#box2 {
transform: scale(1);
mix-blend-mode: difference;
isolation: isolate;
-webkit-filter: blur(5px);
}
|
到这里,可以得到一些结论:
为什么上个例子中元素的堆叠顺序受z-index的影响呢?因为这些元素有些特殊的属性触发它们生存堆叠上下文(stacking context)。
问题来了,什么样的元素会生成堆叠上下文呢?符合下面规则之一的:
position: fixed
always creates a
new stacking context, even when z-index is "auto" (See this post)will-change
even you don't write
themselves directly (See this post)-webkit-overflow-scrolling
set to "touch"在堆叠上下文(stacking context)中 ,子元素的堆叠顺序还是按照上述规则。重点是,子元素的z-index值只在父元素范围内有效。子堆叠上下文被看做是父堆叠上下文中一个独立的模块,相邻的堆叠上下文完全没关系。
总结几句:
渲染的时候,先确定小的stacking context中的顺序,一个小的stacking context确定了以后再将其放在父stacking context中堆叠。有种由内而外,由小及大的感觉。
举例:HTML结果如下,最外层是HTML元素,包含#1 #2 #3,#3中又包含着#4,#5,#6。
Root(HTML)
<!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"; <html
xmlns="" xml:lang="en"> <head>
<title>Understanding CSS z-index: The Stacking Context: Example
Source</title> <style type="text/css"> * { margin: 0; }
html { padding: 20px; font: 12px/20px Arial, sans-serif; } div {
opacity: 0.7; position: relative; } h1 { font: inherit; font-weight:
bold; } #div1, #div2 { border: 1px solid #696; padding: 10px;
background-color: #cfc; } #div1 { z-index: 5; margin-bottom: 190px; }
#div2 { z-index: 2; } #div3 { z-index: 4; opacity: 1; position:
absolute; top: 40px; left: 180px; width: 330px; border: 1px solid #900;
background-color: #fdd; padding: 40px 20px 20px; } #div4, #div5 {
border: 1px solid #996; background-color: #ffc; } #div4 { z-index: 6;
margin-bottom: 15px; padding: 25px 10px 5px; } #div5 { z-index: 1;
margin-top: 15px; padding: 5px 10px; } #div6 { z-index: 3; position:
absolute; top: 20px; left: 180px; width: 150px; height: 125px; border:
1px solid #009; padding-top: 125px; background-color: #ddf;
text-align: center; } </style> </head> <body> <div
id="div1"> <h1>Division Element #1</h1>
<code>position: relative;<br/> z-index: 5;</code>
</div> <div id="div2"> <h1>Division Element
#2</h1> <code>position: relative;<br/> z-index:
2;</code> </div> <div id="div3"> <div id="div4">
<h1>Division Element #4</h1> <code>position:
relative;<br/> z-index: 6;</code> </div>
<h1>Division Element #3</h1> <code>position:
absolute;<br/> z-index: 4;</code> <div id="div5">
<h1>Division Element #5</h1> <code>position:
relative;<br/> z-index: 1;</code> </div> <div
id="div6"> <h1>Division Element #6</h1>
<code>position: absolute;<br/> z-index: 3;</code>
</div> </div> </body> </html> View Code
效果:
分析一下:
1、因为设置了div {opacity: 0.7; position: relative;},所以#1~#6的z-index都是有效的。
2、为什么#4的z-index比#1高,但是却在#1下面?因为#4的z-index虽然值大,但它的作用域在包含块#3内,而#1的z-index的作用域在html内,和#3同属html,而#3的z-index小于#1。
3、为什么#2的z-index值比#5的大,还在下面?同上。
4、#3的z-index是4,但该值和#4,#5,#6的z-index不具有可比性,它们不在一个上下文环境。
5、如何轻易的判断两个元素的堆叠顺序?
z-index对堆叠顺序的控制类似于排版时候一大章下几个小节的样子,或者版本号中一个大的版本号跟着小版本号。
Root-z-index值为默认auto,即0
想看更多例子,可参考文章最后的资源链接。
transform
除了建立新的局部层叠上下文外,还会干一件事:改变绝对定位子元素的包含块。须注意的是,固定定位也是绝对定位的一种。
什么是包含块?有时候一些盒子根据矩形盒计算自身定位和大小,此矩形盒即包含块。更多详情请阅读视觉格式化模型详述。
固定定位元素
固定定位元素的包含块由视口创建(如果读者了解视觉格式化模型详述的信息,也就知道这一点:在计算其“静态位置”的时候,则以初始化包含块作为其计算包含块)。现在我们看以下源代码:
CSS
div { width: 100px; height: 100px; } #fixed { position: fixed; width: 100%; height: 100%; top: 0; left: 0; background: blue; } #transform { background: red; padding: 20px; } <body> <div id="transform"> <div id="fixed"></div> </div> </body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
div {
width: 100px;
height: 100px;
}
#fixed {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: blue;
}
#transform {
background: red;
padding: 20px;
}
<body>
<div id="transform">
<div id="fixed"></div>
</div>
</body>
|
这个时候,以视口为包含块进行定位和大小计算, fixed 将会铺满整个屏幕。
但现在,我们加上如下规则:
CSS
#transform { transform: scale(1); }
1
2
3
|
#transform {
transform: scale(1);
}
|
此时,fixed 的包含块不再是视口,而是 transform 的内边距盒的边缘盒了。故此时 fixed 的宽高均为 140px。
绝对定位元素
我们举一个例子:
CSS
#relative { position: relative; width: 100px; height: 100px; background: green; } #absolute { position: absolute; width: 100%; height: 100%; top: 0; left: 0; background: blue; } #transform { background: red; width: 50px; height: 50px; } <div id="relative"> <div id="transform"> <div id="absolute"></div> </div> </div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#relative {
position: relative;
width: 100px;
height: 100px;
background: green;
}
#absolute {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: blue;
}
#transform {
background: red;
width: 50px;
height: 50px;
}
<div id="relative">
<div id="transform">
<div id="absolute"></div>
</div>
</div>
|
此时 absolute 的包含块为 relative 的内边距盒的边缘盒。由此 absolute 的宽高均为 100px。然后我们添加如下规则:
CSS
#transform { transform: scale(1); }
1
2
3
|
#transform {
transform: scale(1);
}
|
由于 transform 创建了局部层叠上下文,absolute 的包含块不再是 relative 而是 transform 了,根据这一新的包含块,得新宽和高为 50px。
1 赞 1 收藏 评论
前文曾经提到,根元素以及z-index
非auto
的“positioned”元素可以会创建新的层叠上下文,这也是CSS2.1规范唯一提到的,但是在CSS3中,创建层叠上下文的触发条件有了修改,在MDN中有如下描述:
文档中的层叠上下文由满足以下任意一个条件的元素形成:
- 根元素 (HTML),
- 绝对(absolute)定位或相对(relative)定位且 z-index 值不为”auto”,
- 一个 flex 项目(flex item),且 z-index 值不为 “auto”,也就是父元素 display: flex|inline-flex,
- 元素的 opacity 属性值小于 1(参考 the specification for opacity),
- 元素的 transform 属性值不为 “none”,
- 元素的 mix-blend-mode 属性值不为 “normal”,
- 元素的 isolation 属性被设置为 “isolate”,
- 在 mobile WebKit 和 Chrome 22 内核的浏览器中,position: fixed 总是创建一个新的层叠上下文, 即使 z-index 的值是 “auto” (参考 这篇文章),
- 在 will-change 中指定了任意 CSS 属性,即便你没有定义该元素的这些属性(参考 这篇文章)
- 元素的 -webkit-overflow-scrolling 属性被设置 “touch”
如果现有三个堆叠的层,从上到下分别为:DIV3,DIV2,DIV1,设置时以100为间隔,设置DIV1的z-index为0,DIV2的z-index为100,设置DIV3的z-index为200。这样后期如果需要在DIV1和DIV2之间加入一些层的话,以10为间隔,设置z-index为10,20等。再需要向z-index0和z-index10之间加入一层的话以5为间隔。这样的写法可以方便后期扩展添加内容。
尽量避免给z-index使用负值。当然不是绝对的,比如在做图文替换的时候可以使用负值。
在这里,我们看到了那个令人惊讶的opacity
,原来它也创建了一个新的层叠上下文。为什么opacity
小于1时需要创建新的层叠上下文呢?在CSS3-color中有这样的解释。
Since an element with opacity less than 1 is composited from a single offscreen image, content outside of it cannot be layered in z-order between pieces of content inside of it. For the same reason, implementations must create a new stacking context for any element with opacity less than 1.
由于一个opacity
小于1的元素需要依靠这个元素以外的图像来合成,因此它外部内容不能根据z-index
被层叠到该元素的内容中间(子元素也会变得透明,如果存在z-index
不为auto
的“positioned”子元素,那么这些子元素就需要与外部元素进行层叠计算,透明部分就会有奇怪的计算结果),因此它需要创建一个新的层叠上下文,以防止外部内容对该元素的透明化内容造成影响。
那么opacity
对实际的层叠会有什么影响呢?规范中这样描述的:
If an element with opacity less than 1 is not positioned, implementations must paint the layer it creates, within its parent stacking context, at the same stacking order that would be used if it were a positioned element with ‘z-index: 0’ and ‘opacity: 1’. If an element with opacity less than 1 is positioned, the ‘z-index’ property applies as described in [CSS21], except that ‘auto’ is treated as ‘0’ since a new stacking context is always created. See section 9.9 and Appendix E of [CSS21] for more information on stacking contexts. The rules in this paragraph do not apply to SVG elements, since SVG has its own rendering model ([SVG11], Chapter 3).
opacity
小于1的“non-positioned”元素,它就会被当作一个z-index: 0
且opacity: 1
的“positioned”元素一样,来进行层叠计算(前文规则中的第6层);opacity
小于1的“positioned”元素,它将按照前文中z-index
的层叠规则计算技术,只不过,即使z-index
是auto
,仍然会创建层叠上下文;回到之前讨论“不设置z-index的层叠”时用到的例子:
XHTML
<body> <div id="flodiv2">DIV #1</div> <div id="normdiv">DIV #2</div> <div id="flodiv2">DIV #3</div> <div id="normdiv">DIV #4</div> <div id="absdiv2">DIV #5</div> </body>
1
2
3
4
5
6
7
|
<body>
<div id="flodiv2">DIV #1</div>
<div id="normdiv">DIV #2</div>
<div id="flodiv2">DIV #3</div>
<div id="normdiv">DIV #4</div>
<div id="absdiv2">DIV #5</div>
</body>
|
将DIV#3
的opacity
设置为0.7
,显示结果如下:
所有的opacity
小于1的元素都是“positioned”,z-index
默认为auto
,即为0,根据规则6(层叠级数为0的子元素以及“positioned”且层叠级数为0的后代元素),它将不是浮动元素,而是一个“positioned”且层叠级数为0的元素,因此它将会被绘制到DIV#1
之上(如果opacity
为1,它应该是在DIV#1
之下的);
如果仅将DIV#4
设置opacity: 0.9
,那么结果会是:
那么DIV#4
就是opacity
小于1的non-positioned
元素,它将同样被当成z-index: 0
且opacity: 1
的
“positioned”元素一样,即是规则6(层叠级数为0的子元素以及“positioned”且层叠级数为0的后代元素),由于它与其他元素都处于z-index: 0
,因此根据DOM树的顺序,它将仅在DIV#5
之下。(即使将其他所有元素都设置opacity
小于1,那么所有的这些元素都是根据规则6进行层叠计算,那么结果就是根据DOM树顺序产生)
Problem solved!!!
至于其他触发条件,就不再一一分析了。
MDN z-index
understanding css z-index
w3c z-index
一、z-index z-index用来控制元素重叠时堆叠顺序。 适用于 :已经定位的元素(即position:relative/absolute/fixed)。 一...
z-index
后,必须将position
设置为fixed
、absolute
或relative
才回使z-index
创建新的层叠上下文或生效;<html>
)拥有一个根层叠上下文;opacity
及一些其他新的CSS3属性的设置也可能创建新的层叠上下文,这些属性的引入让层叠计算变得更加复杂;z-index
为负值的子元素;z-index
为0的“positioned”元素;z-index
大于等于1的“positioned”子元素;层叠上下文是个比较少接触的概念,但这又是一个非常重要的概念,它决定了元素的层叠顺序的计算方式,尤其是利用z-index
对元素层叠进行控制的时候,如果不理解层叠上下文的概念,就容易遇到各种各样奇怪的问题,有时候,这些问题被错误的归结为浏览器的“BUG”。实际上,大多数浏览器都是根据规范干活的,不要轻易地怀疑浏览器,而是要去看看规范中是怎样定义规则的。
本文大量参考并引用MDN上的文字和源码,并在其基础上作些许改动以求更简单明了的解释。如果对源码有疑问,请先去MDN上参考相关源码和文献。
本文是基于我对层叠上下文的学习和理解记录而成,由于自己是初学者,不敢保证文中所有观点都是正确的,因此我的观点仅作参考,若发现文中有错误,欢迎大家指出,我会尽快作出修正。
Specifying the stack level: the ‘z-index’ property
Understanding CSS z-index
Stacking without z-index
Stacking and float
CSS Stacking Context里那些鲜为人知的坑
css3-color-#transparency
CSS z-index 属性的使用方法和层级树的概念
position 属性和 z-index 属性对页面节点层级影响的例子
1 赞 2 收藏 评论
本文由星彩网app下载发布于前端技术,转载请注明出处:不起眼的,层叠上下文