深入理解z-index

简介: 要解决的问题 在页面编写的过程中,经常需要处理元素的重叠。重叠的顺序不当则容易造成元素被错误地遮盖等现象。一般地,有很多人认为只需要指定元素的z-index即可调整重叠的顺序,但是实际上并不是这样的。

要解决的问题

在页面编写的过程中,经常需要处理元素的重叠。重叠的顺序不当则容易造成元素被错误地遮盖等现象。一般地,有很多人认为只需要指定元素的z-index即可调整重叠的顺序,但是实际上并不是这样的。

重新理解页面维度

当我们打开一个网页,我们会看到一个二维的世界。在这个二维的世界里,页面里的box(盒子)各有自己的x坐标和y坐标。比如,在下图所示的页面结构里面,有四个div元素。它们分别具有自己的宽和高,而每个box左上角的x和y坐标就分别是这个box在页面中的x和y坐标。因而,在我们直观的感知里,页面是二维的。

8f1b4c1f013ada51e1810bc69026b1f3c2eadc83

然而,页面实际上还有第三个维度。垂直于x轴与y轴的方向,存在一个c轴。c轴的正方向指向用户。对于一个页面上的box,它一定有一个c坐标。注意,此处的c坐标并不是z-index。下图中的坐标名有误,z应该是c。

0800b3a63bafb86576008df954ab62a25176ce71

两个重叠的box最能证明这第三个维度的存在,如果页面上有两个元素是重叠的,那么浏览器的渲染引擎必须决定哪一个box的重叠部分要被放在前面。决定的方法很简单,就是直接比较这两个元素的c坐标。c坐标大的那一个,就被渲染在前面;反之,则被压在下面。

你不能把c坐标的大小理解成离用户的远近,因为如果那样理解,那么应该有“近大远小”现象。然而事实上,c坐标大的box并不会变小,只是被浏览器渲染在c坐标小的box前面而已。就好像在现实生活中,我们把两张卡片叠在一起,它们会有上下之分,但是看起来两张卡片的大小并不会有所改变(因为它们足够薄且小)。会产生近大远小现象的应该是z坐标,学过一点空间几何的人都应该熟悉。这也是我称这个维度为c坐标而非z坐标的原因。

下面我们一起来探究一下页面box之间是如何重叠的,换句话说,浏览器是怎么决定一个box的c坐标的。

默认重叠

对于重叠的元素,浏览器默认会按下面的顺序重叠。编号越大的box类型,所拥有的c坐标就越大,因此排在前面。

正常流当中的block level的box

浮动的元素

正常流当中inline level或者inline-block level的box

position值不是static(非正常流中)的box

这里并不是完整的列表,因为我略去了一些后面才会提到的内容。下面是一个示例:

4e036061c935dff85de0276c20a682cc7c3452dd

可以看到,上述四种不同类型的box中,具有最大c坐标的是第4种,它能够覆盖其他所有三种元素。

你需要注意的一点是,不要用DOM树的结构来理解重叠。DOM树中下一级的box完全可以重叠在上一级box之上。这都和Stacking Context有关,我们接下来就详细解释一下。

Stacking-Context

上述四种box类型的重叠规律,当且仅当这些box在同一个Stacking Context的时候生效。不同Stacking Context中的box之间的重叠在下面会提到。

什么是Stacking Context?假设你正在玩贴纸,将很多贴纸贴到同一张纸上,并且贴纸之间可能产生重叠。Stacking Context就像是这张纸。浏览器首先按照默认的重叠规律,将同一个Stacking Context下的所有元素排好顺序,然后按照这个顺序渲染到Stacking Context上。例如,在下面的DOM结构中,有5个box,其中node1是一个Stacking Context,其他的都不是。

d55c9c9c79df0e4665d0fd6f97f3b0a4654f51ae

在渲染的时候,浏览器将node1当做画板,其他box都是贴纸。在决定贴纸顺序的时候,浏览器是不会考虑它们DOM结构上的父子关系的。也就是说,node3-1完全可以被渲染在node2-1的后面,只要在前面所说的默认重叠顺序中,node3-1具有的c坐标比node2-1来得低即可。

整个“贴纸”的过程如下图。可以看到,浏览器在当前Stacking Context中,无视了“贴纸”们的DOM结构之间的关系,而是通过我们前面提到的默认重叠顺序决定“贴纸”的先后关系。决定之后,浏览器将所有“贴纸”贴到Stacking Context上,这个过程称作Composite(组合)。

c77b41631d29a01a03a7b3d20cb9804320513e15

什么样的元素是一个Stacking-Context

符合下面要求的页面box,都是一个Stacking Context。

根元素(html元素)

position是absolute或者relative,并且z-index不是auto的元素

是flex item,并且z-index不是auto的元素

opacity值小于1的元素

在mobile webkit以及Chrome 22+中,position: fixed的元素

多个Stacking-Context之间的重叠

由上面产生Stacking Context的条件,我们可以知道,一个页面上一般有多个Stacking Context。那么多个Stacking Context之间如何决定重叠顺序呢?浏览器一般按下面的规则来决定其顺序,这实际上就是之前我们提到的默认重叠顺序的完整版。

Stacking Context的背景和边框

具有负的z-index的,且position值不是static(非正常流中)的子box的Stacking Context,且z-index数值越小,其c坐标越小

正常流当中的block level的box

浮动的元素

正常流当中inline level或者inline-block level的box

position值不是static(非正常流中)的box,且z-index为0或者auto

具有正的z-index的,且position值不是static(非正常流中)的子box的Stacking Context,且z-index数值越小,其c坐标越小

你需要注意到的是,z-index只能作用在position值不是static的box上方能起效。下面的例子可以说明多个Stacking Context之间的重叠规律。

b3944987873271344fa95b9eb523f8f8c947876f

在这里,.wrapper、#b1和#b2分别都是一个Stacking Context。#b1和#b2是.wrapper的子Stacking Context,浏览器会首先组合#b1以及组合#b2,之后再将#b1和#b2组合到.wrapper上。由于#b1具有正的z-index,而#b2具有负的z-index,所以#b1被组合到了#b2的上面。

你可以试着把#b1的z-index改成-2,那么它就变成了第二类的box(和#b2一样),又因为它的z-index比#b2来得小,所以它会被组合到#b2之后。

总结

z-index只在同一个Stacking Context的组合过程中,参与各个子box的重叠顺序的决定。但是页面box的重叠关系并非仅仅和z-index有关。清楚地认识z-index的工作原理,有助于你写出更有效率的样式表。

原文发布时间为:2018-10-11

原文作者:桃翁

本文来自云栖社区合作伙伴“前端桃园”,了解相关信息可以关注“前端桃园”。

相关文章
|
8月前
|
存储 缓存 监控
解决分布式系统演进过程中数据一致性问题的方法
【10月更文挑战第24天】解决分布式系统演进过程中数据一致性问题是一个复杂而又重要的任务。需要综合运用多种方法和技术,根据具体的系统需求和场景,选择合适的解决方案。同时,不断地进行优化和改进,以适应不断变化的分布式系统环境。
345 47
|
9月前
|
存储 Linux
Linux文件管理(超详细讲解)
Linux文件管理(超详细讲解)
560 5
|
5月前
|
弹性计算 JavaScript 前端开发
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
|
缓存 关系型数据库 MySQL
MySQL数据库——InnoDB引擎-架构-内存结构(Buffer Pool、Change Buffer、Adaptive Hash Index、Log Buffer)
MySQL数据库——InnoDB引擎-架构-内存结构(Buffer Pool、Change Buffer、Adaptive Hash Index、Log Buffer)
188 3
|
8月前
|
人工智能 自然语言处理 数据可视化
什么是AIGC?如何使用AIGC技术辅助办公?
2分钟了解AIGC技术及其如何提高日常办公效率!
3137 4
什么是AIGC?如何使用AIGC技术辅助办公?
|
10月前
|
JavaScript 前端开发 Java
基于springboot的留守儿童爱心网站
这是一个基于SpringBoot的留守儿童爱心网站,包含管理员和用户两种角色。管理员负责用户、新闻、志愿活动、捐赠等管理;用户可进行登录注册、爱心捐赠及活动报名。项目采用SpringBoot与Mybatis作为后端框架,前端则使用HTML和VUE。适用于JDK1.8、IDEA/Eclipse、MySQL5.7/8.x,无需特定Tomcat或Maven版本,支持Windows系统。
201 13
基于springboot的留守儿童爱心网站
|
9月前
|
运维 监控 持续交付
运维之道:从新手到高手的蜕变之路
【10月更文挑战第14天】 在当今这个数字化时代,运维作为保障系统稳定运行的重要岗位,其重要性不言而喻。本文将带你走进运维的世界,探索从一名运维新手成长为行业高手的过程。我们将一起了解运维的基本职责、面临的挑战以及必备的技能和知识。通过实际案例分析,揭示如何在实践中不断提升自己的能力,最终实现职业生涯的飞跃。无论你是即将踏入这个行业的新人,还是已经在行业中摸爬滚打多年的老手,相信本文都能为你提供一些有价值的启示和指导。
183 2
|
9月前
|
Ubuntu Linux 程序员
一个9年archlinux重度使用者自述
一个9年archlinux重度使用者自述
|
9月前
|
IDE Android开发 iOS开发
探索安卓与iOS系统的技术差异:开发者的视角
本文深入分析了安卓(Android)与苹果iOS两大移动操作系统在技术架构、开发环境、用户体验和市场策略方面的主要差异。通过对比这两种系统的不同特点,旨在为移动应用开发者提供有价值的见解,帮助他们在不同平台上做出更明智的开发决策。