代码改变世界

z-index 解析

2013-06-17 21:04  二当家的  阅读(1282)  评论(1编辑  收藏  举报

很多人对z-index的认识仅止于:z-index是控制元素在页面中的堆叠顺序,z-index值高的元素显示在z-index值低的前面。而其中的原因才很少有人去深究,直到自己在实际项目中碰到由于z-index而导致的各种bug时,才会搜索一下解决的办法。但z-index其实是包含着属于自己一套浏览器解析规则的,只要了解了这其中的规则,那么控制页面中的元素便随心所欲了。

z-index的使用条件

只对有 position 属性的且值不为static的元素才有效

堆栈上下文

一组具有共同双亲的元素,按照堆栈顺序一起向前或向后移动构成了所谓的堆栈上下文。充分理解堆栈上下文是真正掌握z-index和堆栈顺序工作原理的关键。

堆栈上下文有三种方法可以在一个元素上形成:(针对标准的浏览器,IE系列有点小区别)

  1. 当一个元素是文档的根元素时(<html>元素)
  2. 当一个元素有一个position值而不是static,有一个z-index值而不是auto
  3. 当一个元素有一个opacity值小于1

前两种形成堆栈上下文的方法具有很大意义并且被广大Web开发者所理解(即使他们不知道这些被叫做什么)。第三种方法(opacity)几乎从来没在w3c说明文档之外被提及过。

示例

span{display: block;width: 50px;height: 50px;position: absolute;}
.red{background-color: red;}
.green{background-color: green;margin: 15px;}
.blue{background-color: blue;margin: 30px;}

<div><span class="red"></span></div>
<div><span class="green"></span></div>
<div><span class="blue"></span></div>

显示为:

 

 

当修改css

 red{background-color: red;z-index: 100;position: relative;}

再添加一条css规则

div:first-child{opacity: 0.99;}

 

再添加

div:first-child{opacity: 0.99;z-index: 1;position: relative;}

 

从上面可以看出,一个元素的堆叠顺序,不仅仅取决于它自身的z-index,更要看它所处在的堆栈上下文,如果所处的上下文的层级很低,即使他本身的z-index设置的很高,也无法实现你的要求。

上面的例子中使用的是opaciry<1的方式来生成一个堆栈上下文的,红色的方块在其父级没有创建堆栈上下文的时候,给他添加一个高的z-index,可以实现覆盖绿色和蓝色的方块,当给红色方块的父级div添加了opacity<1的时,产生了一个堆栈上下文,此时它的z-index设置的再高也无法覆盖绿蓝了,它的z-index只能相对于同样在这个堆栈上下文中的元素起作用,而无法影响到不在这个上下文中的元素。

而如果想要再次覆盖绿蓝方块的话,只能将这整个堆栈上下文的z-index值提高,也就是给红色方块的父级div加一个z-index。用一句话说,就是拼爹的时候到了!如果你在项目中发现你给一个元素设置再高的z-index也不起作用的时候,就要检查一下他的父级,祖先了,是否产生了一个堆栈上下文,将后代元素限制了。如果是的话,要么修改这个元素的属性使其不再产生堆栈上下文,要么就给这个上下文设置一个较高的符合自要求的z-index值。

上面讨论的z-index解析规则都是基于标准的符合w3c规范的浏览器,如果浏览器都遵循规范的话,前端的世界就清爽多了,但IE系列的浏览器总是让你要多费一番功夫。

IE中z-index跟标准浏览器中的解析有一个小小的区别,那就是上面说的产生堆栈上下文中的三个条件中,对第二个条件的支持的区别,在标准浏览器中元素必须是有z-index值的同时要有position属性,且值不为static,满足这两个条件,才会产生一个新的堆栈上下文,但低版本的IE中就不管这么多了,只要你设置了position值不为static,他就会生成一个新的堆栈上下文。

这里就直接引用代码了:

<style> 
  .parent
{width:200px; height:200px; padding:10px;}
  .sub
{text-align:right; font:15px Verdana;width:100px; height:100px;}
  .lt50
{left:50px;top:50px;}
</style>
<
div style="position:absolute; background:lightgrey;" class="parent">
  <div style="position:absolute;z-index:20;background:darkgray;" class="sub">20</div>
  <div style="position:absolute;z-index:10;background:dimgray;" class="sub lt50">10</div>
</
div>
<
div style="position:absolute;left:80px;top:80px;background:black;" class="parent">
  <div style="position:absolute;z-index:2;background:darkgray;" class="sub">2</div>
  <div style="position:absolute;z-index:1;background:dimgray;" class="sub lt50">1</div>
</
div>

很明显,灰色容器和黑色容器是同级的,遵循后来居上的原则,黑色容器是在灰色容器之上的,在低版本IE中因为两容器都设置了postion属性,新生成了堆栈上下文,因此,即便1,2 的z-index 小于 20,10,但由于所处的堆栈上下文整体环境要高,因此,1、2以及黑色容器的层级要高于灰色的容器及其内部的所有元素。而标准模式中容器没有生成堆栈上下文,因此,20,10,2,1以及两个容器的层级都是按照之前说的解析规则来算的。

解决的办法

就像在解决触发了ie中hasLayout而没有触发标准中的BFC那样,只要在可能出现定位元素相互覆盖的情况时,明确指定定位元素的 z-index的值,就可以避免此类的情况。

参考资料