前言

最近,在项目中遇到一个关于CSS中元素z-index属性的问题,具体问题不太好描述,总结起来就是当给元素和父元素色设置position属性和z-index相关属性后,页面上渲染的元素层级结果和我预想的不一样。根据自己之前的理解,也没找到一个合理的解释。我知道,肯定是我对相关属性的细节理解存在问题,所以结合官方文档和在网上各种搜集整理,明白了其中的原因。写下这篇文章,和大家分享有关CSS中层叠上下文层叠等级层叠顺序以及z-index相关的一整套技术细节。

如果存在什么错误或重要遗漏或者有什么疑问,欢迎留言指正、讨论!感谢!

本文已同步至我的个人主页。更多内容,欢迎访问我的GitHub主页,谢谢关注和支持!

一个“片面”的理解

以往,由于自己使用z-index的频率不大,所以对这个CSS属性存在比较片面的认识。一直认为z-index就是用来描述定义一个元素在屏幕Z轴上的堆叠顺序。z-index值越大在Z轴上就越靠上,也就是离屏幕观察者越近。最后才发现这个认识存在很大的问题:

  1. 首先,z-index属性值并不是在任何元素上都有效果。它仅在定位元素(定义了position属性,且属性值为非static值的元素)上有效果。
  2. 判断元素在Z轴上的堆叠顺序,不仅仅是直接比较两个元素的z-index值的大小,这个堆叠顺序实际由元素的层叠上下文层叠等级共同决定。

要想完全理解一个东西,首先要明白它是什么,也就是它的定义。我们先看看上面提到的层叠上下文层叠等级层叠顺序都是什么?定义又太过抽象,后面会再用一个具象的比喻来让你彻底明白它们到底是什么,有什么联系。

什么是“层叠上下文”

层叠上下文(stacking context),是HTML中一个三维的概念。在CSS2.1规范中,每个盒模型的位置是三维的,分别是平面画布上的X轴Y轴以及表示层叠的Z轴。一般情况下,元素在页面上沿X轴Y轴平铺,我们察觉不到它们在Z轴上的层叠关系。而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖。

如果一个元素含有层叠上下文,(也就是说它是层叠上下文元素),我们可以理解为这个元素在Z轴上就“高人一等”,最终表现就是它离屏幕观察者更近。

具象的比喻:你可以把层叠上下文元素理解为理解为该元素当了官,而其他非层叠上下文元素则可以理解为普通群众。凡是“当了官的元素”就比普通元素等级要高,也就是说元素在Z轴上更靠上,更靠近观察者。

什么是“层叠等级”

那么,层叠等级指的又是什么?层叠等级(stacking level,叫“层叠级别”/“层叠水平”也行)

  • 在同一个层叠上下文中,它描述定义的是该层叠上下文中的层叠上下文元素在Z轴上的上下顺序。
  • 在其他普通元素中,它描述定义的是这些普通元素在Z轴上的上下顺序。

说到这,可能很多人疑问了,不论在层叠上下文中还是在普通元素中,层叠等级都表示元素在Z轴上的上下顺序,那就直接说它描述定义了所有元素在Z轴上的上下顺序就OK啊!为什么要分开描述?

为了说明原因,先举个栗子:

具象的比喻:我们之前说到,处于层叠上下文中的元素,就像是元素当了官,等级自然比普通元素高。再想象一下,假设一个官员A是个省级领导,他下属有一个秘书a-1,家里有一个保姆a-2。另一个官员B是一个县级领导,他下属有一个秘书b-1,家里有一个保姆b-2。a-1和b-1虽然都是秘书,但是你想一个省级领导的秘书和一个县级领导的秘书之间有可比性么?甚至保姆a-2都要比秘书b-1的等级高得多。谁大谁小,谁高谁低一目了然,所以根本没有比较的意义。只有在A下属的a-1、a-2以及B下属的b-1、b-2中相互比较大小高低才有意义。

再类比回“层叠上下文”和“层叠等级”,就得出一个结论:

  1. 普通元素的层叠等级优先由其所在的层叠上下文决定。
  2. 层叠等级的比较只有在当前层叠上下文元素中才有意义。不同层叠上下文中比较层叠等级是没有意义的。

如何产生“层叠上下文”

前面说了那么多,知道了“层叠上下文”和“层叠等级”,其中还有一个最关键的问题:到底如何产生层叠上下文呢?如何让一个元素变成层叠上下文元素呢?

其实,层叠上下文也基本上是有一些特定的CSS属性创建的,一般有3种方法:

  1. HTML中的根元素<html></html>本身j就具有层叠上下文,称为“根层叠上下文”。
  2. 普通元素设置position属性为static值并设置z-index属性为具体数值,产生层叠上下文。
  3. CSS3中的新属性也可以产生层叠上下文。

至此,终于可以上代码了,我们用代码说话,来验证上面的结论:

栗子1:
有两个div,p.a、p.b被包裹在一个div里,p.c被包裹在另一个盒子里,只为.a、.b、.c设置positionz-index属性

  1. <style>
  2. div {
  3. position: relative;
  4. width: 100px;
  5. height: 100px;
  6. }
  7. p {
  8. position: absolute;
  9. font-size: 20px;
  10. width: 100px;
  11. height: 100px;
  12. }
  13. .a {
  14. background-color: blue;
  15. z-index: 1;
  16. }
  17. .b {
  18. background-color: green;
  19. z-index: 2;
  20. top: 20px;
  21. left: 20px;
  22. }
  23. .c {
  24. background-color: red;
  25. z-index: 3;
  26. top: -20px;
  27. left: 40px;
  28. }
  29. </style>
  30. <body>
  31. <div>
  32. <p class="a">a</p>
  33. <p class="b">b</p>
  34. </div>
  35. <div>
  36. <p class="c">c</p>
  37. </div>
  38. </body>

效果:

因为p.a、p.b、p.c三个的父元素div都没有设置z-index,所以不会产生层叠上下文,所以.a、.b、.c都处于由<html></html>标签产生的“根层叠上下文”中,属于同一个层叠上下文,此时谁的z-index值大,谁在上面。

栗子2:
有两个div,p.a、p.b被包裹在一个div里,p.c被包裹在另一个盒子里,同时为两个div和.a、.b、.c设置positionz-index属性

  1. <style>
  2. div {
  3. width: 100px;
  4. height: 100px;
  5. position: relative;
  6. }
  7. .box1 {
  8. z-index: 2;
  9. }
  10. .box2 {
  11. z-index: 1;
  12. }
  13. p {
  14. position: absolute;
  15. font-size: 20px;
  16. width: 100px;
  17. height: 100px;
  18. }
  19. .a {
  20. background-color: blue;
  21. z-index: 100;
  22. }
  23. .b {
  24. background-color: green;
  25. top: 20px;
  26. left: 20px;
  27. z-index: 200;
  28. }
  29. .c {
  30. background-color: red;
  31. top: -20px;
  32. left: 40px;
  33. z-index: 9999;
  34. }
  35. </style>
  36. <body>
  37. <div class="box1">
  38. <p class="a">a</p>
  39. <p class="b">b</p>
  40. </div>
  41. <div class="box2">
  42. <p class="c">c</p>
  43. </div>
  44. </body>

效果:

我们发下,虽然p.c元素的z-index值为9999,远大于p.ap.bz-index值,但是由于p.ap.b的父元素div.box1产生的层叠上下文的z-index的值为2,p.c的父元素div.box2所产生的层叠上下文的z-index值为1,所以p.c永远在p.ap.b下面。

同时,如果我们只更改p.ap.bz-index值,由于这两个元素都在父元素div.box1产生的层叠上下文中,所以,谁的z-index值大,谁在上面。

什么是“层叠顺序”

说完“层叠上下文”和“层叠等级”,我们再来说说“层叠顺序”。“层叠顺序”(stacking order)表示元素发生层叠时按照特定的顺序规则在Z轴上垂直显示。由此可见,前面所说的“层叠上下文”和“层叠等级”是一种概念,而这里的“层叠顺序”是一种规则。

在不考虑CSS3的情况下,当元素发生层叠时,层叠顺讯遵循上面途中的规则。
这里值得注意的是:

  1. 左上角"层叠上下文background/border"指的是层叠上下文元素的背景和边框。
  2. inline/inline-block元素的层叠顺序要高于block(块级)/float(浮动)元素。
  3. 单纯考虑层叠顺序,z-index: autoz-index: 0在同一层级,但这两个属性值本身是有根本区别的。

对于上面第2条,为什么inline/inline-block元素的层叠顺序要高于block(块级)/float(浮动)元素?这个大家可以思考一下!
其实很简单,像border/background属于装饰元素的属性,浮动和块级元素一般用来页面布局,而网页设计之初最重要的就是文字内容,所以在发生层叠时会优先显示文字内容,保证其不被覆盖。

你要的“套路”

上面说了那么多,可能你还是有点懵。这么多概念规则,来点最实际的,有没有一个“套路”当遇到元素层叠时,能很清晰地判断出他们谁在上谁在下呢?答案是——肯定有啊!

1、首先先看要比较的两个元素是否处于同一个层叠上下文中:
      1.1如果是,谁的层叠等级大,谁在上面(怎么判断层叠等级大小呢?——看“层叠顺序”图)。
      1.2如果两个元素不在统一层叠上下文中,请先比较他们所处的层叠上下文的层叠等级。
2、当两个元素层叠等级相同、层叠顺序相同时,在DOM结构中后面的元素层叠等级在前面元素之上。

光说不练假把式

对于技术学习,代码展示是最直观最易懂的方式之一。话不多说,直接上代码,我们通过以下几个“栗子”,来进一步验证掌握上面的结论。

栗子1:

  1. <style>
  2. .box1, .box2 {
  3. position: relative;
  4. z-index: auto;
  5. }
  6. .child1 {
  7. width: 200px;
  8. height: 100px;
  9. background: #168bf5;
  10. position: absolute;
  11. top: 0;
  12. left: 0;
  13. z-index: 2;
  14. }
  15. .child2 {
  16. width: 100px;
  17. height: 200px;
  18. background: #32c292;
  19. position: absolute;
  20. top: 0;
  21. left: 0;
  22. z-index: 1;
  23. }
  24. </style>
  25. </head>
  26. <body>
  27. <div class="box1">
  28. <div class="child1"></div>
  29. </div>
  30. <div class="box2">
  31. <div class="child2"></div>
  32. </div>
  33. </body>

效果:

说明:.box1/.box2虽然设置了position: relative,但是z-index: auto的情况下,这两个div还是普通元素,并没有产生层叠上下文。所以,child1/.child2属于<html></html>元素的“根层叠上下文”中,此时,谁的z-index值大,谁在上面

栗子2:

对于栗子1中的CSS代码,我们只把.box1/.box2z-index属性值改为数值0,其余不变。

  1. .box1, .box2 {
  2. position: relative;
  3. z-index: 1;
  4. }
  5. ...

效果:

说明: 此时,我们发现,仅仅修改了.box1/.box2z-index属性值改为数值0,最终结果完全相反。这时.child2覆盖在了.child1上面。原因是什么呢?很简单:因为设置z-index: 0后,.box1/.box2产生了各自的层叠上下文,这时候要比较.child1/.child2的层叠关系完全由父元素.box1/.box2的层叠关系决定。但是.box1/.box2z-index值都为0,都是块级元素(所以它们的层叠等级,层叠顺序是相同的),这种情况下,在DOM结构中后面的覆盖前面的,所以.child2就在上面。

CSS3中的属性对层叠上下文的影响

CSS3中出现了很多新属性,其中一些属性对层叠上下文也产生了很大的影响。如下:

  1. 父元素的display属性值为flex|inline-flex,子元素z-index属性值不为auto的时候,子元素为层叠上下文元素;
  2. 元素的opacity属性值不是1
  3. 元素的transform属性值不是none
  4. 元素mix-blend-mode属性值不是normal`;
  5. 元素的filter属性值不是none
  6. 元素的isolation属性值是isolate
  7. will-change指定的属性值为上面任意一个;
  8. 元素的-webkit-overflow-scrolling属性值设置为touch

CSS3中,元素属性满足以上条件之一,就会产生层叠上下文。我们用第1条来做一个简单的解释说明。

栗子1:

  1. <style>
  2. .box {
  3. }
  4. .parent {
  5. width: 200px;
  6. height: 100px;
  7. background: #168bf5;
  8. /* 虽然设置了z-index,但是没有设置position,z-index无效,.parent还是普通元素,没有产生层叠上下文 */
  9. z-index: 1;
  10. }
  11. .child {
  12. width: 100px;
  13. height: 200px;
  14. background: #32d19c;
  15. position: relative;
  16. z-index: -1;
  17. }
  18. </style>
  19. </head>
  20. <body>
  21. <div class="box">
  22. <div class="parent">
  23. parent
  24. <div class="child">child</div>
  25. </div>
  26. </div>
  27. </body>

效果:

说明: 我们发现,.child.parent覆盖了。按照“套路”来分析一下:
虽然.parent设置了z-index属性值,但是没有设置position属性,z-index无效,所以没有产生层叠上下文,.parent还是普通的块级元素。此时,在层叠顺序规则中,z-index值小于0.child会被普通的block块级元素.parent覆盖。

对于上面的栗子,我们只修改.box的属性,设置display: flex,其余属性和DOM结构不变。

  1. .box {
  2. display: flex;
  3. }

效果:

说明: 当给.box设置display: flex时,.parent就变成层叠上下文元素,根据层叠顺序规则,层叠上下文元素的background/border的层叠等级小于z-index值小于0的元素的层叠等级,所以z-index值为-1.child.parent上面。

小测试

下面的代码,我会把最终页面渲染的结果放在代码之后,有兴趣的“童鞋”可以分析一下,各个元素的层叠等级,最后来确定这些元素哪个在上哪个在下。

  1. <style>
  2. .parent {
  3. width: 100px;
  4. height: 200px;
  5. background: #168bf5;
  6. position: absolute;
  7. top: 0;
  8. left: 0;
  9. z-index: 0;
  10. }
  11. .child1 {
  12. width: 100px;
  13. height: 200px;
  14. background: #32d19c;
  15. position: absolute;
  16. top: 20px;
  17. left: 20px;
  18. z-index: 1;
  19. }
  20. .child2 {
  21. width: 100px;
  22. height: 200px;
  23. background: #e4c950;
  24. position: absolute;
  25. top: 40px;
  26. left: 40px;
  27. z-index: -1;
  28. }
  29. .child2-1 {
  30. width: 100px;
  31. height: 200px;
  32. background: #e45050;
  33. position: absolute;
  34. top: 60px;
  35. left: 60px;
  36. z-index: 9999;
  37. }
  38. .child2-2 {
  39. width: 100px;
  40. height: 200px;
  41. background: #db68a7;
  42. position: absolute;
  43. top: 80px;
  44. left: 40px;
  45. z-index: -9999;
  46. }
  47. </style>
  48. </head>
  49. <body>
  50. <div class="parent">
  51. parent
  52. <div class="child1">child1</div>
  53. <div class="child2">
  54. child2
  55. <div class="child2-1">child2-1</div>
  56. <div class="child2-2">child2-2</div>
  57. </div>
  58. </div>
  59. </body>

效果:

参考文章

以上的内容有一部分内容参考了以下两位大神的博客,写的很好,也很清晰,推荐大家看一看,你会对相关知识点掌握的更清晰。

张鑫旭-《深入理解CSS中的层叠上下文和层叠顺序》
AMInInsist-《CSS 中的z-index属性》

彻底搞懂CSS层叠上下文、层叠等级、层叠顺序、z-index的更多相关文章

  1. 彻底搞懂CSS文本、空白换行问题

    首先,我们来整理一下与换行有关的3个CSS属性: word-break 该属性决定文本内容超出容器时,浏览器是否自动插入换行符. 属性值: normal:默认换行规则——英文以词为单位换行,连续字符不 ...

  2. 彻底搞懂CSS伪类选择器:is、not

    本文介绍一下Css伪类:is和:not,并解释一下is.not.matches.any之前的关系 :not The :not() CSS pseudo-class represents element ...

  3. css--深入理解z-index引发的层叠上下文、层叠等级和层叠顺序

    前言 在编写css样式代码的时候,我们经常会遇到z-index属性的使用,我们可能只了解z-index能够提高元素的层级,并不知道具体是怎么实现的.本文就来总结一个由z-index 引发的层叠上下文和 ...

  4. CSS——关于z-index及层叠上下文(stacking context)

    以下内容根据CSS规范翻译. z-index 'z-index'Value: auto | <integer> | inheritInitial: autoApplies to: posi ...

  5. CSS基础:层叠顺序和层叠上下文

    简介 在考虑到两个元素可能重叠的情况下,层叠顺序决定了那个元素在前面,那个元素在后面,这是针对普通元素而言.而层叠上下文和块级格式化上下文 (BFC) 一样,基本上也是由一些 CSS 属性创建的,它单 ...

  6. 层叠上下文(The stacking context)

    MDNThe stacking context 层叠上下文是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z轴上延伸,HTML元素依据其自身属性按照优 ...

  7. 层叠上下文 Stacking Context

    层叠上下文 Stacking Context 在CSS2.1规范中,每个盒模型的位置是三维的,分别是平面画布上的x轴,y轴以及表示层叠的z轴.对于每个html元素,都可以通过设置z-index属性来设 ...

  8. 20190409-层叠の层叠上下文、层叠水平、层叠顺序、z-index、伪元素层叠

    写在前面乱七八糟的前言: 此"八卦"的源于,在写下图这个圆滚滚的导航布局时,使用元素及其伪元素加上绝对定位完成,但遇到:before或:after伪元素与元素的层叠顺序,就是伪元素 ...

  9. z-index和层叠上下文

    z-index基础介绍:三维坐标空间里,x轴通常用来表示水平位置,y轴来表示垂直位置,还有z轴来表示在纸面内外方向上的位置,像下面的图片一样: css允许的z-index的值是 ● auto (自动, ...

随机推荐

  1. package.xml使用说明

    1. package.xml使用说明 a. pacakge.xml 包含了package的名称. 版本号. 内容描述. 维护人员. 软件许可. 编译构建工具. 编译依赖. 运行依赖等信息. 2. pa ...

  2. (3)RabbitMQ交换器(Exchange)

    1.前言 上个章节也有简单介绍过RabbitMQ交换器,这里主要了解下它的类型和如何使用.交换器有四种类型,分别是direct.fanout.topic.headers. 2.Virtual host ...

  3. 震撼的Linux全景图:业界成熟的内核架构长什么样?

    1)Linux怎么来的? Linus 为了方便访问大学服务器中的资源 ,在自己的机器上写了一个文件系统和硬盘驱动,这样就可以把自己需要的资源下载到自己的机器中.随后linus把这款操作系统雏形开源,成 ...

  4. 微信小程序 实现图片上传并展示到前端(多文件)并实现表单提交验证

    链接: https://blog.csdn.net/guanj0623/article/details/121595884?spm=1001.2014.3001.5501 https://blog.c ...

  5. tp5文件上传实现缩略图+水印的功能(参考)

    public function AddNews(){ $data = Request::instance()->param(); //接收文件 $file = request()->fil ...

  6. JQ,JQuery的ajax卡住了,浏览器页面卡住

    在使用ajax的时候浏览器卡住了, 经过测试是因为在ajax中使用的data数据变量写错了 不存在也不报错,直接卡主了 好好检查一下吧.

  7. Redis安装——windows版

    下载地址   : https://github.com/MicrosoftArchive/redis/releases/tag/win-3.2.100 双击进行安装,然后将安装目录配置到环境变量里,打 ...

  8. 移动端开发为什么使用@2x@3x图片

    物理.逻辑与位图像素的概念 关于设备物理像素和逻辑像素,这两个像素一个是实体的,一个是抽象的单位.除此之外还有一个不可忽视的像素,就是位图像素. 物理像素(设备像素):指的是设备屏幕实际拥有的像素点. ...

  9. 机器学习之BP神经网络

    import random import math #神经元的定义 class Neuron: def __init__(self,bias): self.bias = bias self.weigh ...

  10. Anaconda 01_安装问题

    一. 创建环境 1.打开cmd  使用如下语句创建环境 conda create -n 环境名  2. 查看当前conda所有环境 conda info --envs  3.激活环境(其中一句) Co ...