说一说z-index容易被忽略的那些特性

前言

关于z-index,每个人都会用,但大多人都不理解其真正的生效机制。最近做项目有很多用到z-index的地方,才发现以前用的一知半解,所以上网查了一些资料梳理了一下。下文参考自!What No One Told You About Z-Index,文中介绍了很多关于z-index使用的关键点。

关于z-index的生效机制并不复杂,但如果不花一点时间研究其特点,有很多关键点容易被忽略。

问题

HTML文档中有三个div元素,每个div中存在一个span元素,三个span元素分别设置背景颜色为red,green,以及blue。然后每个span都设置为position: absolute,三个span的位置稍微错开以便可以仔细观察它们之间的堆叠顺序。然后将第一个span元素的z-index设置为1,其他两个不设置。具体代码如下:

<div>
  <span class="red">Red</span>
</div>
<div>
  <span class="green">Green</span>
</div>
<div>
  <span class="blue">Blue</span>
</div>
.red, .green, .blue {
  position: absolute;
  width: 200px;
  height: 200px;
}
.red {
  background: red;
  z-index: 1;
}
.green {
  background: green;
  top: 50px;
  left: 50px;
}
.blue {
  background: blue;
  top: 100px;
  left: 100px;
}

结果如下:

那么问题来了,尝试在不打破下述规则的前提下将red span置于blue和green span元素之下:

  • 不改变HTML元素的标记
  • 不添加或者改变任何元素的z-index属性
  • 不添加或者改变任何元素的position属性

如果不了解z-index的一些特性,对于上述要求估计会有些烦恼。

解决方案

在第一个div(也就是red span)上面添加一个值小于1的opacity属性,如下所示:

div:first-child {
  opacity: .99;
}

然后就能看到惊讶的效果:

opacity属性居然会影响元素的堆叠顺序,这个结果令人意想不到。

堆叠顺序

z-index表面上的规则似乎很简单,有一个更大z-index的元素会叠放在较小的z-index元素上面。但事实并非如此,这个规则只适用于一个相对的范围。

在HTML文档中有一个不变的堆叠准则,任何一个元素都可以叠放在其他元素之上或者之下,决定元素叠放顺序的规则其实很清晰。

  • 当不包含z-index属性和position属性时,规则很简单,所有元素的叠放顺序与其所在HTML文档中出现的先后顺序一致。(当然使用负margin来重叠内联元素的特例除外。)
  • 当元素浮动float时,浮动块元素被放置于非定位块元素与定位块元素之间,具体的讲,浮动元素显示在普通流中的后代块元素之上,常规流中的后代行内元素之下。
  • 当加入position位置属性时,所有具有position属性的元素及其子元素会显示在其他不具有position属性的元素上面。(本文中具有position属性的元素指代的均是元素的position属性的值为除了static的其他值,如relative、absolute。
  • 当引入z-index属性时,规则稍微变得复杂一点。

1) z-index只在设置了position属性的元素上有效,没有position属性的元素上的z-index属性均不生效。

2) index值会产生堆叠上下文,堆叠上下文将在下一章中详细介绍。

堆叠上下文

拥有共同父元素的一组元素共同前移或者后移即构成了一个堆叠上下文。每个堆叠上下文有一个单一的根元素,当元素上形成一个新的堆叠上下文时,堆叠上下文中的所有子元素按照堆叠顺序被局限在一个固定的区域内。一个堆叠上下文构成一个整体,其内部元素有相对不同的堆叠顺序,但与其他堆叠上下文比较时,只能整体上移或者下移。

通俗的讲,如果某个元素被置于其所在堆叠上下文的最底层,我们是没有办法让它显示在另一个拥有更高堆叠顺序的堆叠上下文的元素之上的,哪怕你将其z-index设置为无限大。

那构成一个堆叠上下文的规则是怎样的呢?有如下情况:

  • 文档的根元素(html元素)。
  • 元素拥有position属性(即position属性为除开static的其他值),同时设置了不为auto的z-index属性值。
  • 元素拥有opacity属性,且其取值小于1。
  • 一些新的css属性,如 filters, css-regions, paged media等需要离屏渲染的属性,均能使元素形成堆叠上下文。
  • 指定position: fixed的元素,即使z-index为auto。

同一堆叠上下文内子元素的堆叠顺序

从底层到上层依次为:

  1. 堆叠上下文的根元素
  2. 设置了position属性,并且z-index为负的元素及其子元素,z-index值较大的元素置于较小值元素之上,同等属性值的元素按照html中出现的先后顺序堆叠。
  3. 没有设置position的元素。
  4. 设置了position属性,并且z-index属性为auto的元素。
  5. 设置了position属性,并且z-index属性为正值的元素。

不同堆叠上下文

  • 堆叠上下文可以嵌入其他堆叠上下文。
  • 每个堆叠上下文和它的同级上下文是独立的。
  • 堆叠上下文中的子元素按照前述顺序摆放。
  • 堆叠上下文内部的子堆叠上下文的z-index只在父堆叠上下文中有意义。

最后

在阐述完堆叠上下文的形成、堆叠上下文之间的堆叠规则,堆叠上下文内的堆叠顺序后,让我们回到文章最开始的问题。

起初元素的叠放顺序如下:

 <div>  //1
  <span class="red"></span>    //6
</div>
<div>  //2
  <span class="green"><span> //4
</div>
<div>  //3
  <span class="blue"></span>  //5
</div>

当添加属性opacity: 0.99后,第一个div形成了一个新的堆叠上下文,red span成为了新的上下文中的第一个子元素。元素结构变为:

 <div>  //1
  <span class="red"></span>    //1.1
</div>
<div>  //2
  <span class="green"><span> //4
</div>
<div>  //3
  <span class="blue"></span>  //5
</div>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏贾志刚-OpenCV学堂

OpenCV中的图形绘制

OpenCV在Core模块中支持多种图形绘制与填充,方便开发者在图像对象识别与检测之后通过特定的图形轮廓加以显式表示。常见的几何形状包括线、矩形、圆形、椭圆,此...

3516
来自专栏章鱼的慢慢技术路

Direct3D 11 Tutorial 4: 3D Spaces_Direct3D 11 教程4:3D空间

在上一个教程中,我们在应用程序窗口的中心成功渲染了一个三角形。 我们没有太注意我们在顶点缓冲区中拾取的顶点位置。 在本教程中,我们将深入研究3D位置和转换的细节...

893
来自专栏Flutter入门

Android OpenGL ES(三)-平面图形

前两章,其实我们已经明白了绘制平面图形的套路了。 接下来我们按照套路继续画其他的图形。

1382
来自专栏我是攻城师

使用python3+opencv3实现的识别答题卡的例子(02)

例子02是ayoungprogrammer博客上参考作者原版C++代码和思路,然后改造成python版本的,先在本地运行成功之后,然后加上自己的理解,给大多数核...

2526
来自专栏Android原创

Android OpenGL ES开发初探

网上介绍很多,这里不多讲,直接简单的讲,OpenGL是一个可以用来画二维或者三维图形库。而OpenGL ES呢,是OpenGL针对嵌入式设备搞的一个库,所以移动...

1728
来自专栏用户2442861的专栏

CSDN-markdown基本语法说明

MathJax是一款运行在浏览器中的开源的数学符号渲染引擎,使用MathJax可以方便的在浏览器中显示数学公式,不需要使用图片。这篇文章介绍如何使用LaTeX...

1472
来自专栏ACM算法日常

翻转瓷砖Fliptile(开关反转)- POJ 3279

Farmer John knows that an intellectually satisfied cow is a happy cow who will g...

882
来自专栏一心无二用,本人只专注于基础图像算法的实现与优化。

一个简单的统计图像主颜色的算法(C#源代码)

      前段日子有朋友咨询了下分析图像主颜色的算法,我对这一块也没有什么深入的研究,参考了一些小代码,然后自己写了一个很简单的小工具,现共享给大家。    ...

2665
来自专栏数据结构与算法

洛谷P3209 [HNOI2010]PLANAR(2-SAT)

题目描述 若能将无向图G=(V,E)画在平面上使得任意两条无重合顶点的边不相交,则称G是平面图。判定一个图是否为平面图的问题是图论中的一个重要问题。现在假设你要...

3196
来自专栏desperate633

LintCode 房屋染色题目代码

这里有n个房子在一列直线上,现在我们需要给房屋染色,分别有红色蓝色和绿色。每个房屋染不同的颜色费用也不同,你需要设计一种染色方案使得相邻的房屋颜色不同,并且费用...

872

扫码关注云+社区