注: 本文参考自张鑫旭大神博客:http://www.zhangxinxu.com/wordpress/2016/01/understand-css-stacking-context-order-z-index/
今天在sf
社区中看到一个问题,在这里简单的还原一下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>层叠上下文</title>
<style type="text/css">
.test-1, .test-2{
width: 100px;
height: 100px;
}
.test-1{
transform: scale(0.8);
background: #000;
}
.test-2{
margin-top: -50px;
background: red;
}
</style>
</head>
<body>
<div class="test-1"></div>
<div class="test-2"></div>
</body>
</html>
产生的效果为:
诶,这个不对啊,完全颠覆了对css布局的认识有没有?正常的情况是应该是后面的div
在覆盖前面的div
啊,而且将第二个的z-index
设置为负值也是没有效果的,要想看清这个问题,我们还需要仔细来看一下其背后的故事。
stacking context(层叠上下文):是指的我们页面中的z轴的相对位置,也就是相对于页面的立体层面上的位置,这个z轴方向也就是指我们眼睛到我们页面的连线 方向。,说道这里很多人会说,这个难道不是我们的z-index
属性干的事情吗?答案是对的,但是z-index
只是我们我们的层叠上下文的冰山一角。
层叠顺序:
在这里我们可以发现,层叠顺序大概可以归类为:装饰层Background/Borders
,布局float/Block
,然后为内容层,同时也可以发现,改变我们的z-index
值可以改变我们的层叠顺序。
归类一下层叠规则(针对于处于同一层叠顺序的元素):
1. 对于z-index
来说,谁大谁在上面
2. 当元素层叠水平的一样,谁在后面谁在上面,也就是后来居上的意思
层叠上下文的特性:
- 每个层叠上下文都是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中,也就是说子元素是存在其父元素的层叠上下文中的,所以比较不同层叠上下文子元素的层叠顺序,需要比较的父元素的层叠顺序。
- 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的层叠上下文。
- 层叠上下文的层叠水平要比普通元素高
怎么创建出来层叠上下文:
the root element
也就是我们所说的<html>
- 相对定位(
position:relative
)或者绝对定位(position: absolute
)的元素并且其z-index
值不为auto
时。
下面来看一个小demo:
<div class="test-3" style="position: relative;">
<img src="images/c2.jpg" alt="java" style="position: relative; z-index: 2;" />
</div>
<div class="test-4" style="position: relative;top: -50px;">
<img src="images/c4.jpg" alt="C++" style="position: relative; z-index: 1;" />
</div>
这时符合我们原先的认知,也就是C++
在下面,用层叠上下文来解释就是,两张图片处于同一个层叠上下文中,层叠顺序遵循的是谁大谁在上面。
然而我们来改动下代码,给我们的.test-3,.test-4
分别添加一个z-index: 0;
,结果就是这样的:
这个是为什么呢?为什么我们的C++
的z-index
比java
小,但是java
却位于我们的上面,原因就是我们的.test-3,.test-4
满足了相对定位且z-index
不为auto
,所以两个div
产生了两个不同的层叠上下文,比较两个不同层叠上下文的层叠顺序,由于z-index
一样,所以遵循的是谁在后面谁就在上面,所以看到我们现在的情况,之所以C++
在上面,是由于其父元素的层叠顺序要比java
父元素的层叠顺序高。
3. 父级元素为flex
布局并且自己的z-index
的值不为auto
flex
是指display
的值为flex
或者inline-flex
,此时形成层叠上下文的并不是被flex
的容器,而是其子元素,来看下我们的demo:
<div style="display: flex;">
<div class="test-3" style="z-index: 0;">
<img src="images/c2.jpg" alt="java" style="position: relative; z-index: 2;" />
</div>
<div class="test-4" style="margin-left: -50px;z-index: 1;">
<img src="images/c4.jpg" alt="C++" style="position: relative; z-index: 1;" />
</div>
</div>
同样可以用我们的层叠上下文特性1来解释,test-3,test-4
形成了层叠上下文。
4. 当元素的opacity
值不为1的时候
<div class="demo-4" style="background: blue;width: 100px;">
<img src="images/c2.jpg" alt="java" style="position: relative; z-index: -1;" />
</div>
产生的效果是这样的:
原因就是我们的img
形成了一个层叠上下文,而我们的demo-4
只是一个block
块级元素,所以才会形成这个样子的情况,在img
已经不在demo-4
所影响的层叠上下文中了,在img
眼中只不过是一个普通盒子。但是假如我们去掉了img
的position: relative;
就会发现我们的z-index
属性会失效,原因就是在img
属于
div
所处的层叠上下文中,这时demo-4
的background
相当于层叠顺序中位于最后一层的层叠上下文的background
,所以无论我们怎么将z-index
设置为多小,img
都会位于background
层上面,那么现在我们给demo-4
添加一个样式opacity: 0.8;
,所以我们可以说在,这时我们的样式会变成:
这时我们的demo-4
也生成了一个新的层叠上下文,其backgound
应该位于最底层。其所以子元素均高于background
层,无论是否形成新的层叠上下文。
5. transform
值不为none
的元素
正如我们文章一开始提到的那个问题一样,.test-2
之所以会在.test-1
下的原因就是.test-1
的transform
不为none
,这时.test-1
形成了层叠上下文,其层叠顺序要高于普通元素的层叠顺序,所以产生了我们问题中所说的那种现象。
6. CSS3中的filter
注意的是这个filter
是css3
的新增属性,我们在使用时要加上浏览器前缀,如:-webkit-filter
。其表现与transform
相似。