默认层级
我们在日常写页面的时候,正常情况下html元素都是按照html文档的顺序进行排布的,也就是写在后面的元素(如DIV),会显示在前一个元素(假设DIV)的下方。这种情况是最简单的,也是最好理解的。但在垂直于屏幕的Z轴方向上,浏览器是如何决定哪个元素渲染在上面,哪个元素渲染在下面的呢?先来看下面这段demo
<style>
#a{
width: 100px;
height: 100px;
background: red;
}
#b{
width: 100px;
height: 100px;
background: blue;
margin-top: -50px;
margin-left: 50px;
}
</style>
<div id='a'>I AM A DIV</div>
<div id='b'>I AM B DIV</div>
在上面的demo中,我们将蓝色div的margin设置为负值,让它与红色div重叠。正如我们看到的那样,蓝色div盖在了红色div的上面。也不难理解,因为在代码中蓝色div是写在红色div后面的,所以浏览器在渲染的时候,先绘制了红色div,然后再绘制蓝色div。
Z-index
那在上面的demo中,我们加入zindex属性会变成什么样呢?
<style>
#a{
width: 100px;
height: 100px;
background: red;
}
#b{
width: 100px;
height: 100px;
background: blue;
margin-top: -50px;
margin-left: 50px;
position: relative;
z-index: -1;
}
</style>
<div id='a'>I AM A DIV</div>
<div id='b'>I AM B DIV</div>
给蓝色div加上z-index属性,并将值设置为-1的时候,能看到蓝色div被渲染在了红色div的下方。这说明z-index属性对html元素的渲染层级是有影响的。但z-index值越高,渲染的层级就一定越高吗?
Transform
<style>
#a{
width: 100px;
height: 100px;
background: red;
}
#b{
width: 100px;
height: 100px;
background: blue;
margin-top: -50px;
margin-left: 50px;
position: relative;
z-index: -1;
}
#c{
width: 100px;
height: 100px;
background: green;
position: relative;
z-index: 1000;
margin-top: -50px;
margin-left: -25px;
}
</style>
<div id='a'>I AM A DIV</div>
<div id='b'>I AM B DIV
<div id='c'>I AM C DIV</div>
</div>
这里给蓝色div新增了一个子元素,该元素为绿色背景。我们将其z-index值设置为一个很大的值1000。如果按照上面z-index越大,渲染层级越高的猜测,那么绿色div应该在红色div的上层,但看的到实际情况并不是这样。这说明z-index还是被某个神秘力量限制住了。接下来就要涉及到层叠栈(stacking context)
的概念。
层叠栈(stacking context)
可以简单理解为一个渲染单元,浏览器在进行渲染的时候,会独立计算这个独立单元的层级。在上面的demo中,蓝色div与绿色div为一个层叠栈,无论怎么给这两个div设置z-index值,都只会影响该栈上下文中的渲染层级。如果想要将绿色div渲染在红色div之上,那么有两种方法,一种是将绿色div的代码移到与红色div平级的位置,此时同属一个层叠栈。另一种是将红色div的z-index值设置的比蓝色div所在的层叠栈小,那么蓝色div所属的层叠栈会渲染在红色div之上。
那有没有什么奇淫技巧能在不使用上述两个方法的情况下,让红色div渲染在绿色div和蓝色div之间的呢?CSS博大精深,一定有办法。
在CSS中,还有一种能改变Z轴渲染逻辑的属性,就是transform。
<style>
#a{
width: 100px;
height: 100px;
background: red;
}
#b{
width: 100px;
height: 100px;
background: blue;
margin-top: -70px;
margin-left: 25px;
position: relative;
z-index: -1;
}
#c{
width: 100px;
height: 100px;
background: green;
position: relative;
z-index: 1000;
margin-top: 25px;
margin-left: 25px;
transform: translateZ(1px);
}
#container{
transform-style: preserve-3d;
}
</style>
<div id='container'>
<div id='a'>I AM A DIV</div>
<div id='b'>I AM B DIV
<div id='c'>I AM C DIV</div>
</div>
</div>
上面demo中,在所有div前再包一层div,并设置CSS属性transform-style: preserve-3d
将该层叠栈3D化。此时我们如果想要将绿色div渲染在红色div上,只需要给绿色div设置transform
属性,并往Z轴正方向移动大于0px的距离即可。
总结
-
html元素的渲染层级,默认情况下是按照html内元素的书写顺序来的。
-
通过z-index可以打破这个规则,但z-index只在同一个
层叠栈(stacking context)
中有效。 -
通过transform可以打破
层叠栈(stacking context)
的规则,让元素可以跨栈调整渲染层级。