关于z-index的真正问题是,很少有人理解它到底是怎么用。其实它并不复杂,但是如果你从来没有花一定时间去看具体的z-index相关文档,那么你很可能会忽略一些重要的信息。

不相信我吗?好吧,看看你能否解决下面这个问题:

问题:

在 接下来的HTML里 有三个<div>元素,并且每个<div>里包含一个<span>元素。每 个<span>被分别给定一个背景颜色:红、绿、蓝。每个<span>被放置到文档的左上角附近,部分重叠着其他 的<span>元素,这样你就可以看到哪些是被堆叠在前面。第一个<span>有一个z-index的值为1,而其他两个没有任 何z-index值。

以下就是这个HTML和它的基本CSS。

HTML代码

1
2
3
4
5
6
7
8
9
<div>
<span>Red</span>
</div>
<div>
<span>Green</span>
</div>
<div>
<span>Blue</span>
</div>

CSS代码

1
2
3
4
5
6
7
8
9
10
11
12
13
.red, .green, .blue {
position: absolute;
}
.red {
background: red;
z-index: 1;
}
.green {
background: green;
}
.blue {
background: blue;
}

挑战:

尝试使红色<span>元素堆在蓝色和绿色<span>的后面,不要打破以下规则:

  • 不要以任何方式改变HTML标记
  • 不要添加/修改任何元素的z-index属性
  • 不要添加/修改任何元素的position属性

如果你找到了答案,那么它应该像下面这样:

1
2
3
4
5
6
7
8
9
<div>
<span>Red</span>
</div>
<div>
<span>Green</span>
</div>
<div>
<span>Blue</span>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
div:first-child {
opacity: .99;
}
.red, .green, .blue {
position: absolute;
}
.red {
background: red;
z-index: 1;
}
.green {
background: green;
}
.blue {
background: blue;
}

解决方案:

这个解决方法是在第一个<div>里(红色<span>的父节点)添加一个小于1的opacity属性值。下面就是被添加的CSS的例子:

1
2
3
div:first-child {
opacity: .99;
}

如果你现在很震惊,但是仍然百思不得其解,并且不相信opacity能决定哪个元素堆在前面,欢迎来社区提问,当第一次在这个问题上被困扰时我同样很震惊。

希望接下来的内容能够让你对这个问题更清楚些。

堆栈顺序

Z-index看上去如此简单:高的z-index堆在低的z-index的前面,对吗?这实际上是错的,是z-index问题的一部分。它看上去如此的简单,以至于很多开发者没有花相应的时间去读相关的规则。

每一个在HTML文档中的元素既可以在其他元素的前面,也可以在其他元素的后面。这就是所谓的堆栈顺序。决定这个顺序的规则被十分清楚的定义在说明文档中,但是就像之前我已经提到过,这些文档没有被大多数开发者们完全弄明白。

当z-index和position属性不被包括在内时,这些规则相当简单:基本上,堆栈顺序和元素在HTML中出现的顺序一样。(好吧,其实是有一点复杂的,但是只要你不使用压缩边界来重叠行内元素,你可能不会遇到边界问题。)

当你把位置属性也包括在内介绍时,任何定位元素(和他们的子元素)都在非定位元素前被显示出来。(说一个元素被“定位”意思是它有一个不同于静态的位置值,例如相对的,绝对的,等等。)

最 后,当z-index被提及时,事情变的有点儿复杂。最初,很自然的假设带有高z-index值的元素会在带有低z-index值的元素前面,但是后来发 现没那么简单。首先,z-index只对定位元素起作用。如果你尝试对非定位元素设定一个z-index值,那么肯定不起作用。其次,z-index值能 创建堆栈上下文环境,并且突然发现看似简单的东西变的更加复杂了。

堆栈上下文

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

每 一个堆栈上下文都有一个HTML元素作为它的根元素。当一个新的堆栈上下文在一个元素上形成,那么这个堆栈上下文会限制所有的子元素以堆栈的顺序存储在一 个特别的地方。那意味着一旦一个元素被包含在处于底部堆栈顺序的堆栈上下文中,那么就没有办法先出现于其他处于更高的堆栈顺序的不同堆栈上下文元素,就算 z-index值是十亿也不行!

现在,堆栈上下文有三种方法可以在一个元素上形成:

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

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

用堆栈顺序决定一个元素的位置

实际上,为一个页面上的所有元素决定全局堆栈顺序(包括边界、背景、文本节点、等等)是极度复杂的,并且远远超越了本文讲述的范围(再一次,参考文档)。但是我们最大的目的,就是基本了解这个顺序,它能够在很长一段时间内帮助我们提高CSS开发的可预测性。所以,让我们打破顺序,分解为独立的堆栈上下文。

在同样的堆栈上下文里的堆栈顺序

下面是几条基本的规则,来决定在一个单独的堆栈上下文里的堆栈顺序(从后向前):

  1. 堆栈上下文的根元素
  2. 定位元素(和他们的子元素)带着负数的z-index值(高的值被堆叠在低值的前面;相同值的元素按照在HTML中出现的顺序堆叠)
  3. 非定位元素(按照在HTML中出现的顺序排序)
  4. 定位元素(和他们的子元素)带着auto的z-index值(按照在HTML中出现的顺序排序)
  5. 定位元素(和他们的子元素)带着正z-index值(高的值被堆叠在低值的前面;相同值的元素按照在HTML中出现的顺序堆叠)

注 解:定位元素带有负的z-index值被在一个堆栈上下文中先排序,这意味着他们出现在所有其他元素的后面。正因如此,它使一个元素出现在自己父元素之后 成为可能,这以前通常是不可能的事。当然,这局限于它的父元素与它在同一个堆栈上下文,并且不是那个堆栈上下文的根元素。一个伟大的例子如Nicolas Gallagher的CSS不用图像降低阴影

全局堆栈顺序

坚定的理解了为什么/什么时候新的堆栈上下文形成,同时掌握了同一个堆栈上下文的堆栈顺序,现在让你来找出一个特定元素将出现在全局堆栈里的顺序不是那么糟糕了吧?

避免错误的关键是能够发现新的堆栈上下文什么时候形成。如果你对一个元素设置了z-index值为十亿但是它没有在堆栈顺序中向前移动,检查一下它的祖先树,看是否它的父节点形成了堆栈上下文。如果是那样的话,你的z-index值即使有十亿也不会给你带来好处。

包扎救治

回到之前的原始问题,我已经重建了这个HTML的结构,添加了一些注释,每一个标签指明了它在堆栈里的顺序。这个顺序是假设最初的CSS。

1
2
3
4
5
6
7
8
9
<div><!-- 1 -->
<span><!-- 6 --></span>
</div>
<div><!-- 2 -->
<span><!-- 4 --><span>
</div>
<div><!-- 3 -->
<span><!-- 5 --></span>
</div>

当我们添加opacity到第一个<div>,堆栈顺序像下面这样改变:

1
2
3
4
5
6
7
8
9
<div><!-- 1 -->
<span><!-- 1.1 --></span>
</div>
<div><!-- 2 -->
<span><!-- 4 --><span>
</div>
<div><!-- 3 -->
<span><!-- 5 --></span>
</div>

span.red曾经的顺序是6,但现在改为1.1。我已经使用“.”来标注一个新的上下文环境的形成。span.red现在是那个新的上下文的第一个元素。

现 在似乎更清晰了,关于为什么红色盒子跑到其他盒子的后面。原始的例子只包含两个堆栈上下文,根元素和形成span.red的那个。当我们添加 opacity到span.red的父节点上,形成了第三个堆栈上下文,结果显示在span.red上的z-index值只能应用在那个新的堆栈上下文 中。因为第一个<div>(应用opacity的那个)和它的兄弟元素没有position或者z-index值的集合,他们的堆栈顺序是由 他们在HTML里的源顺序决定的,也就是说第一个<div>,和它的堆栈上下文里的所有元素被第二个和第三个<div>元素分 离。

关于z-index的那些事儿的更多相关文章

  1. Shadow Map阴影贴图技术之探 【转】

    这两天勉勉强强把一个shadowmap的demo做出来了.参考资料多,苦头可不少.Shadow Map技术是目前与Shadow Volume技术并行的传统阴影渲染技术,而且在游戏领域可谓占很大优势.本 ...

  2. 运用<div>布局页面练习

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. 关于Cewu Lu等的《Combining Sketch and Tone for Pencil Drawing Production》一文铅笔画算法的理解和笔录。

     相关论文的链接:Combining Sketch and Tone for Pencil Drawing Production 第一次看<Combining Sketch and Tone f ...

  4. 四种比较简单的图像显著性区域特征提取方法原理及实现-----> AC/HC/LC/FT。

    laviewpbt  2014.8.4 编辑 Email:laviewpbt@sina.com   QQ:33184777 最近闲来蛋痛,看了一些显著性检测的文章,只是简单的看看,并没有深入的研究,以 ...

  5. C# 金钱 小写转大写的算法

    调用 ConvertMoney的ConvertMoneyToWords(decimal money)方法即可 using System; using System.Collections.Generi ...

  6. 【Unity3D】利用Shader以及更改Mesh实现2D游戏的动态阴影效果

    最近看到一个非常有趣的益智小游戏,是一个盗贼进入房子偷东西的, 其实这种游戏市面上已经很多了,吸引我的是那个类似手电筒的效果, 主角走到哪里,光就到哪里,被挡住的地方还有阴影.有点类似策略游戏里的战争 ...

  7. 来看看css3中的box-shadow

    不谈IE,只谈谈box-shadow的具体使用方法 语法: E {box-shadow: <length> <length> <length>?<length ...

  8. img和css背景的选择

    在什么情况下更适合使用HTML IMG标签来显示一个图像,而不是一个CSS有背景图像,反之亦然? 如下场景使用img标签比较合适: 1.如果图像是等内容的一部分或图表或人(真正的人,而不是股票图人), ...

  9. 深入理解CSS中的层叠上下文和层叠顺序(转)

    by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=5115 零.世间的道 ...

  10. 2016 年青岛网络赛---Family View(AC自动机)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5880 Problem Description Steam is a digital distribut ...

随机推荐

  1. springboot项目中jdk版本的问题

    几经周折,在idea中修改了多次jdk编译为1.8,可是一编译就恢复到默认的1.7版本. 在经过多次这个博客的修改内容: https://blog.csdn.net/li396864285/artic ...

  2. 20145215《网络对抗》Exp8 Web基础

    20145215<网络对抗>Exp8 Web基础 基础问题回答 什么是表单? 表单是一个包含表单元素的区域,表单元素是允许用户在表单中(比如:文本域.下拉列表.单选框.复选框等等)输入信息 ...

  3. python3 操作MYSQL实例及异常信息处理--用traceback模块

    # 用traceback模块查看异常import traceback import pymysql db = pymysql.connect(host='localhost', user='root' ...

  4. Hadoop生态圈-基于yum源的方式部署Cloudera Manager5.15.1

    Hadoop生态圈-基于yum源的方式部署Cloudera Manager5.15.1 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我之前分享过关于离线方式部署Cloudera ...

  5. Anaconda的安装和更新

    下载地址官网:https://www.anaconda.com/distribution/ 一.安装 二.下载安装完成后我们来检验一下是否安装成功 点击“开始” —— “Anaconda3(64-bi ...

  6. [C++]指针与引用(应用辨析)

    1.指针变量允许将一个整数经强制转换后赋值给指针变量    Eg:      float *fp;      fp = (float *)5000;//意义:将5000作为一个地址赋给指针变量fp 2 ...

  7. Java类的5个加载步骤

    类加载的五个过程分为: 加载 验证 准备 解析 初始化 1 加载 完成三件事: 通过类的全限定名来获取定义此类的二进制字节流 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构 在内存中生成 ...

  8. if语句与switch语句

    if语句可以替代switch语句,但是switch语句不能完全替代if语句.比如下面这种就是不对的 switch (len) { case (len <= 4): domLen = 4; bre ...

  9. Java的三种代理模式:静态代理/JDK动态代理/Cglib动态代理

    1.静态代理:需要定义接口或者父类,目标对象与代理对象均实现同一接口或继承同一父类. 2.JDK动态代理:需要目标对象实现一个接口,通过动态反射的机制,生成代理对象,实现同一个接口 3.Cglib动态 ...

  10. Android ThreadPool

    在Android开发中,如果我们要执行某个耗时任务,一般都会考虑开启一个线程去处理. 一个线程run方法执行完毕后,才算真正结束:但是,这只是结束,并没有被回收:会一直闲置在那里,等待GC去回收.所以 ...