原文地址:What You May Not Know About the Z-Index Property 原文做者:Steven Bradley 译者:Chor
z-index
这个属性表面看上去很简单,但若是你想搞清楚其工做原理的话,实际上是有很多值得探讨之处的。本文将从层叠上下文(stacking contexts)和一些实际案例出发,谈一谈 z-index
的内部工做原理。css
CSS 为盒模型的布局提供了三种不一样的定位方案[1] :html
-
正常文档流 -
浮动 -
定位
最后一种方案(特指绝对定位)将会把元素从正常文档流中彻底移走,其最终的落脚点将取决于开发者。前端
经过设置 top
,left
,bottom
和 right
的值,你能够在二维空间中对元素进行定位,但 CSS 同时也容许你使用 z-index 属性[2] 把它放置在三维空间中。web
表面看起来,z-index
彷佛是一个很简单的属性,你给它设置哪一个值,元素就会位于 y 轴的哪一个位置,就这样。但它实际上并无咱们想象的这么简单,这个属性背后是一系列决定元素所在层级的规则。微信
为了保证咱们在同一个“频道”上,这里我先普及一些基础概念,以后再解释层叠的相关知识,并在一些场景中体会 z-index[3] 做用的机制。app
Z-Index 的基础概念
对于三维空间坐标系,你确定很熟悉了。x 轴表明水平方向,y 轴表明垂直方向,z 轴则表明咱们的目光向页面(屏幕)看进去的时候,各元素的布局状况。编辑器

因为屏幕是一块二维平面,咱们实际上并无真的看到 z 轴,更多的是经过透视的形式。具体地说,多个元素共享同一块二维平面时,有的元素在顶部,有的元素在底部,咱们由此感觉到了 z 轴的存在。ide
为了决定某个元素在 z 轴方向上的位置,CSS 容许咱们为 z-index 属性设置三种值[4]:布局
-
auto(默认值) -
整数 -
inherit
咱们主要看一下整数值。它能够是正整数、负整数或者 0,值越大,元素就离咱们“越近”,值越小,元素天然也就离咱们“越远”。学习
若是两个元素在定位以后共享同一块二维空间,那么在这块空间中, z-index
越大的元素将可能覆盖 z-index
较小的元素。
很显然,上面讲的这些都是很是容易理解的,而且也和咱们的直觉相符合。不过,下面的问题恐怕就不是很好回答了:
-
当设置了定位和 z-index
的元素与一个位于正常文档流中的元素重叠时,哪个在顶层呢? -
一个元素设置定位,另外一个元素设置浮动,哪个在顶层呢? -
若是父元素和子元素都设置了定位,会发生什么事?
为了更好地理清这些问题,咱们有必要进一步理解与 z-index
工做原理相关的一些概念,也就是层叠上下文、层叠等级和层叠顺序。
层叠上下文和层叠等级
针对层叠上下文和层叠等级[5] ,可能很难给出一个清晰易懂的概念,因此咱们这里用通俗的例子来理解。想象一下,如今有一张桌子,上面摆满了各类东西。那么这张桌子就表明了一个层叠上下文,假设还有另外一张与之并排的桌子,那么就产生了另外一个层叠上下文。

如图所示,层叠上下文 1 指的就是文档根部,而层叠上下文 2 和 3 位于 1 的某个层叠等级中。此外,这两个层叠上下文各自会包含新的层叠等级。
如今想象一下,第一张桌子上面并排摆了四个砖头,这四个砖头上面放着一个玻璃杯,而玻璃杯上面还放着一个水果盘。那么,砖头、玻璃杯、水果盘,各自都处于不一样的层叠等级中,但它们共处于“桌子”这一层叠上下文中。
对每个网页来讲,默认都会建立一个层叠上下文[6] ,这个上下文(这张桌子)的根部就是 html
元素,html
元素的全部子元素都会位于这个默认的层叠上下文中的某个层叠等级,就比如东西会摆放在桌子的不一样位置上同样。
当你给某个元素设置一个非 auto
的 z-index
时,就会建立一个新的 层叠上下文[7],它和它所包含的层叠等级都是独立于其它层叠上下文和层叠等级的,就比如你搬了一张新的桌子放在房间里,它和旧的桌子是互相独立的。
层叠顺序
咱们能够经过一个很是简单的例子来理解层叠顺序,这个例子甚至还不须要涉及到 定位元素[8] 。
想象一下,如今有一个很是简单的网页,不考虑默认的 <html>
, <head>
, <body>
等元素,就只须要考虑每一个网页至少都会有的一个 <div>
。在 CSS 文件中设置 html
的背景颜色为蓝色,设置 div
的背景颜色为红色,并设置宽高。
当加载页面的时候,你以为会看到什么?
这个天然不用多想,引入眼帘的确定是一大片的蓝色,同时还有一个此前设置好尺寸的红色块级元素。除非你作了额外的设置,不然这个元素将正常地出如今左上角。
你可能会说“就这?太简单了吧”,不过有一个问题可能不那么简单:为何红色的块级元素就必定会位于蓝色背景的上层呢?为何咱们看到的就是 div
位于 html
的上层呢?缘由是,它们都遵循了层叠顺序的规则。
在这个简单的例子中,根据规则,正常文档流的子块(div
)的层级将会高于根元素(html
)的背景和边框。咱们看到div
位于顶层,这是由于它的层叠等级更高。
虽然上面这个例子只涉及到了两个层叠等级,但实际上,在一个层叠上下文中,一共可能出现七个层叠等级,从最低到最高排列,依次是:
-
背景和边框 :造成层叠上下文的元素的背景和边框,它是整个上下文中层叠等级最低的。 -
Z-Index 为负数 :设置了 z-index
为负数的子元素以及由它所产生的层叠上下文 -
块级盒模型:位于正常文档流中的、块级的、非定位的子元素 -
浮动盒模型 :浮动的、非定位的子元素 -
内联盒模型 :位于正常文档流中的、内联的、非定位的子元素 -
Z-index 为 0:设置了 z-index
为 0 的、定位的子元素以及由它所产生的层叠上下文 -
Z-Index 为正数 :设置了 z-index
为正数的、定位的子元素以及由它所产生的层叠上下文,它是整个上下文中层叠等级最高的

这七个层叠等级就构成了层叠顺序的规则。符合层叠等级七的元素,会比层叠等级在一到六的元素更“贴近咱们”,符合层叠等级五的元素,会比层叠等级二的元素更“贴近咱们”,以此类推。
第一次学习这些层叠规则的时候,我感受收获了不少新的东西。若是只着眼于层叠等级2、六和七(也就是涉及到 z-index
的等级),那么大部分时候,咱们对于 z-index
的理解是正确的。正的 z-index
的层级比 0 要高,而 0 又比负的要高,一切都符合直觉,可能大多数人到这里就不继续日后探究了。
我以前就是这样,在看到这些规则以前,觉得除了正的和负的 z-index
,其它状况均可以看做是 z-index
为0 —— 不过如今咱们很清楚了,这种想法是错误的。事实是,大部分元素的层级都要低于 z-index:0
。
还有一个有趣的细节是,非定位的元素实际位于四种不一样的层叠等级中。乍一想以为很奇怪,不过其实这是很合理的。假设全部的非定位元素都位于同一个层叠等级,那么咱们就没办法在 div
(块级盒)上看到文本(内联盒)了。
来看个案例
我前面提到过不少次,当你给一个元素设置非 auto 的 z-inde
时,会建立一个新的、彻底独立的层叠上下文。
从新回顾一下以前拿桌子作比喻的案例。一开始的时候,咱们的桌子上摆满了四块砖头,上面是一个玻璃杯,再上面是一个水果盘。如今,假设又有一张新的桌子,它摆放的东西和旧桌子差很少,惟一的不一样是,新桌子少了一个水果盘。
不难想象,旧桌子的水果盘是整个房间中位于最顶层的物品(它有最大的 z-index
),不过,若是把旧桌子以及它上面的全部东西总体搬到地下室呢?此时,水果盘的层级会比新桌子上的每个物品都要低,这是由于,放置水果盘的旧桌子总体已经低于新桌子了。
对于网页上的定位元素来讲,其实道理是同样的。假设有以下代码,思考一个问题:div.two
和 div.four
,哪一个在上哪一个在下?
HTML:
<div class="one">
<div class="two"></div>
<div class="three"></div>
</div>
<div class="four"></div>
CSS:
div {
width: 200px;
height: 200px;
padding: 20px;
}
.one, .two, .three, .four {
position: absolute;
}
.one {
background: #f00;
outline: 5px solid #000;
top: 100px;
left: 200px;
z-index: 10;
}
.two {
background: #0f0;
outline: 5px solid #000;
top: 50px;
left: 75px;
z-index: 100;
}
.three {
background: #0ff;
outline: 5px solid #000;
top: 125px;
left: 25px;
z-index: 150;
}
.four {
background: #00f;
outline: 5px solid #ff0;
top: 200px;
left: 350px;
z-index: 50;
}
尽管 div.two
有更高的 z-index
(100),但在页面上,它的层级实际上比 div.four
(z-index
为50)要低。下图就是页面元素的层级状况,根据黑色和黄色边框,咱们能够区分每一个元素生成的不一样的层叠上下文。

因为 div.two
位于 div.one
中,因此它的 z-index
是和 div.one
的层叠上下文相关的,也就是说,实际表现出来的 z-index
是下面这样的:
-
.one —— z-index = 10 -
.two —— z-index = 10.100 -
.three —— z-index = 10.150 -
.four —— z-index = 50
div.one
和内部包含的一切将会在层级上低于 div.four
,不管给 div.one
的子元素设置多大的 z-index
,子元素的层级都没法超过 div.four
。
看到这个例子是否是有一种熟悉的味道?我也曾经被 z-index
这么坑过一两次。咱们都曾疑惑一个问题,为何一个 z-index
很是大的元素,在层级上始终没法超过一个 z-index
比它小不少的元素?相信在学习了这些案例以后,你已经豁然开朗了。
总结
在最初学习 z-index
的时候,咱们都会认为它很简单,这不就是表明元素在 z 轴上的位置吗?不过咱们如今知道了,事情远没有这么简单。深刻理解 z-index[9] 一文也揭示了 z-index
背后一些原理层面的东西,包括层叠上下文,层叠等级以及一系列决定元素的层叠顺序的规则。
最后,记住一个很重要的结论:定位元素能够建立新的层叠上下文,在这个上下文中的全部层叠等级,都会高于或者低于另外一个层叠上下文的全部层叠等级。
拓展阅读
-
What No One Told You About Z-Index by Philip Walton -
The Z-Index CSS Property: A Comprehensive Look on Smashing Magazine -
How Well Do You Understand CSS Positioning? -
The stacking context on Mozilla Developer Network -
Z-Index And The CSS Stack: Which Element Displays First?
参考资料
定位方案: https://www.w3.org/TR/CSS2/visuren.html#positioning-scheme
[2]z-index 属性: http://www.w3.org/TR/CSS2/visuren.html#layers
[3]z-index: http://www.vanseodesign.com/css/css-stack-z-index/
[4]z-index 属性设置三种值: http://www.w3.org/TR/CSS21/visuren.html#propdef-z-index
[5]层叠上下文和层叠等级: http://timkadlec.com/2008/01/detailed-look-at-stacking-in-css/
[6]层叠上下文: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context
[7]层叠上下文: http://www.w3.org/TR/CSS21/zindex.html
[8]定位元素: http://www.vanseodesign.com/css/css-positioning/
[9]深刻理解 z-index: http://coding.smashingmagazine.com/2009/09/15/the-z-index-css-property-a-comprehensive-look/
点个『在看』支持下
本文分享自微信公众号 - 前端技术江湖(bigerfe)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。