【CSS in Depth 2 精译_042】6.4 CSS 中的堆叠上下文与 z-index(下)——深入理解堆叠上下文

当前内容所在位置(可进入专栏查看其他译好的章节内容)

  • 第一章 层叠、优先级与继承(已完结)
  • 第二章 相对单位(已完结)
  • 第三章 文档流与盒模型(已完结)
  • 第四章 Flexbox 布局(已完结)
  • 第五章 网格布局(已完结)
  • 【第六章 定位与堆叠上下文】 ✔️
    • 6.1 固定定位
      • 6.1.1 创建一个固定定位的模态对话框
      • 6.1.2 在模态对话框打开时防止屏幕滚动
      • 6.1.3 控制定位元素的大小
    • 6.2 绝对定位
      • 6.2.1 关闭按钮的绝对定位
      • 6.2.2 伪元素的定位问题
    • 6.3 相对定位
      • 6.3.1 创建下拉菜单(上)
      • 6.3.2 创建 CSS 三角形(下)
    • 6.4 堆叠上下文与 z-index ✔️
      • 6.4.1 理解渲染过程与堆叠顺序(上)
      • 6.4.2 用 z-index 控制堆叠顺序(上)
      • 6.4.3 深入理解堆叠上下文(下) ✔️​
    • 6.5 粘性定位(精译中 ⏳)
    • 6.6 本章小结

《CSS in Depth》新版封面

《CSS in Depth》新版封面

译者按
在 6.4 节的上篇,我们用 z-index 轻松处理了下拉菜单挡住模态对话框的问题。接下来的下篇将带您深入了解堆叠上下文的相关概念。其实按照二八定律,这块内容是很多前端大牛口中的“仅作了解”的知识点;对此我持保留意见。他们这么说,无非是以过来人的身份提前剧透。但仅作了解的真正含义,我认为应该是先啃下这块硬骨头:弄清核心概念、基本原理、适用场景,以便今后能快速切入。前端要了解的知识点确实不少,但能否将遇到的陌生知识点转化为您真正的“基础知识”,前期的勤学苦练是半点都不能马虎的。一旦第一次学没彻底搞懂,后面再学难度就会明显增大,因为之前那些错误的理解会在最要紧的关头冷不丁跳出来扰乱视听,以致于行差踏错,功败垂成。在开发圈子混久了慢慢就会明白一个道理:出来混,迟早是要还的。

6.4.3 深入理解堆叠上下文 Understanding stacking contexts

所谓的 堆叠上下文(stacking contexts,是由浏览器一同绘制(painted together)的一个或多个元素组成。其中的一个元素会作为堆叠上下文的根元素(root)。比如,当给一个已设置定位的元素加上 z-index 时,它就成了该堆叠上下文的根元素;其所有后代元素则相应变为该堆叠上下文的一部分。

事实上,将堆叠上下文里的所有元素一同绘制会造成严重的后果:堆叠上下文以外的元素将永远无法叠放在该上下文内部的任意两个元素之间。也就是说,如果一个元素叠放在了某个堆叠上下文的前面,那么该元素将不会被后方堆叠上下文里任一元素所覆盖;同理,如果一个元素被放在了堆叠上下文的后面,那它将永无翻身之日,堆叠上下文中的任一元素无论怎么设置都不会让该元素挡在前面。

这么说可能有点绕,下面结合一个最简单的应用场景来演示说明。新建一个 HTML 页面,并按照代码清单 6.12 给出的 HTML 标记更新页面:

图 6.12 堆叠上下文示例 HTML 标记

<div class="box one positioned">
  one
  <div class="absolute">nested</div>
</div>
<div class="box two positioned">two</div>
<div class="box three">three</div>

这段代码包含三个内容盒子,其中有两个被设置为定位元素,其 z-index 的值均为 1;而位于第一个定位元素中的绝对定位元素,其 z-index 的值为 100。虽然后者的属性值很大,但最终还是被渲染到了第二定位元素的后面,只因其父元素(即第一个定位元素)形成的堆叠上下文位于第二个内容盒的 后方(如图 6.13 所示)。

图 6.13 整个堆叠上下文相对于页面上其他元素进行叠放

【图 6.13 整个堆叠上下文相对于页面上其他元素进行叠放】

上述效果的 CSS 样式如代码清单 6.10 所示。将它们更新到本地页面。其中大部分样式用于设置尺寸大小与颜色,以便区分堆叠顺序。元素间的重叠效果还是用负的外边距实现。当中最核心的代码,莫过于给每个元素设置 positionz-index 的部分了:

代码清单 6.13 创建堆叠上下文的样式代码

body {
  margin: 40px;
}
 
.box {
  display: inline-block;
  width: 200px;
  line-height: 200px;
  text-align: center;
  border: 2px solid black;
  background-color: #ea5;
  margin-left: -60px;  /* 实现元素重叠效果 */
  vertical-align: top;
}
 
.one { margin-left: 0; }
.two { margin-top: 30px; }
.three { margin-top: 60px; }

/* 每个定位元素都分别创建了一个 z-index 值为 1 的堆叠上下文 */
.positioned {
  position: relative;
  background-color: #5ae;
  z-index: 1;
}
 
.absolute {
  position: absolute;
  top: 1em;
  right: 1em;
  background-color: #fff;
  border: 2px dashed #888;
  z-index: 100;  /* z-index 只对该元素所在的堆叠上下文中的堆叠顺序生效 */
  line-height: initial;
  padding: 1em;
}

根据堆叠上下文的相关概念,叠放在第二个盒子下面的第一个盒子其实是它所在堆叠上下文的根元素。正因如此,即便当中的绝对定位元素给到一个很高的 z-index 值,依旧无法覆盖在第二个盒子上面。大家不妨在浏览器的开发者工具里试验一下,以便更好地理解这种堆叠关系。试着改改每个元素的 z-index 值,看看效果究竟如何。

注意

添加 z-index 值并非创建堆叠上下文的唯一途径,比如 opacity 属性,在属性值小于 1 时也能创建,类似的属性还有 transformfilter 等等。此外,固定定位和粘性定位(sticky positioning,将在本章 6.5 节介绍)即便不指定 z-index 值也能创建一个堆叠上下文。而 HTML 文档的根节点(document root,即 <html> 元素)则会为整个页面创建一个 顶级堆叠上下文(top-level stacking context)

堆叠上下文中的所有元素会按照以下顺序,从后往前依次叠放:

  • 堆叠上下文的根元素;
  • z-index 为负值的定位元素,及其子元素;
  • 非定位(Non-positioned)元素;
  • z-index 值为 auto 的定位元素,及其子元素;
  • z-index 为正值的定位元素,及其子元素。

用变量来跟踪 z-index 的值

如果不根据页面各组件的优先级划分出条理清晰的堆叠顺序,那么页面样式表很容易演变为一场 z-index 混战。没有清晰的说明,开发人员在给一个模态框之类的元素设计样式时,为了防止被其他元素遮挡,很可能会指定一个高得离谱的 z-index,比如 999999。像这样反复折腾几遍后,后续给新组件指定 z-index 值就只能凭感觉和运气了。

为避免情况失控,可以使用 CSS 的自定义属性(custom properties,详见第 2 章 2.6 节相关内容)来统一管理:将所有 z-index 值定义为变量并放到同一个地方集中管理(如下所示)。这样就能一目了然地看出那些元素在前、那些元素在后了:

--z-loading-indicator: 100;
--z-nav-menu:          200;
--z-dropdown-menu:     300;
--z-modal-backdrop:    400;
--z-modal-body:        410;

步长增量建议预留为 10 或者 100,以便今后根据实际情况进行增补。

要是发现 z-index 的行为不符合预期,记得在 DOM 数中定位到该元素的祖先节点,直至锁定堆叠上下文的根节点;然后调整其 z-index 属性,将整个堆叠上下文前移或后置。此外,遇到多个堆叠上下文相互嵌套的情况,操作时务必慎之又慎。

当页面很复杂时,可能很难准确判断是哪个堆叠上下文出的问题。因此,在创建之初就得多加小心,防患于未然。没有特殊理由最后不要随意创建堆叠上下文,尤其是遇到元素包含了很大一块内容的时候,这一点尤为重要。再者,要尽量将模态框这样的独立定位元素放到 DOM 结构的最外层、紧邻关闭标签 </body> 之前,这样一来就没有什么外部的堆叠上下文能束缚住它们了。

一些开发人员会忍不住给页面大量元素设置定位。一定要克制这种冲动。定位用得越多,网页就越复杂,也就越难以调试。如果已经定位了大量元素,不妨回过头来重新评估一下当前的状况,尤其是当发现自己很难调试出想要的效果时,一定要反思。如果可以用别的方案实现当前的布局效果,应当优先选用那些方案。

相比手动设置定位来实现某个布局,如何能够依靠文档流实现同样的效果,那么浏览器会帮我们处理好很多边界情况。切记:CSS 定位会让元素移出文档流(positioning takes elements out of the document flow)。一般来说,只有在需要将元素叠放到其他元素之前时,才会考虑 CSS 定位。



关于《CSS in Depth》(中译本书名《深入解析 CSS》)

第 1 版第 2 版
读者评分原版:4.7(亚马逊);中文版:9.3(豆瓣)原版:5.0(亚马逊);中文版:暂无,待出版
出版时间原版:2018 年 3 月;中文版:2020 年 4 月原版:2024 年 7 月;中文版:暂无,待出版
原价原版:$44.99;中文版:¥139.00原版:$59.99;中文版:暂无,待出版
现价原版:$36.49;中文版:¥52.54 起步原版:$52.09;中文版:暂无,待出版
原版国内预订起步价 ¥461.00起步价 ¥750.00

本专栏为该书第 2 版高分译文专栏,全网首发,精译精校,持续更新,计划今年内完成全书翻译,敬请期待!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安冬的码畜日常

您的鼓励是我持续优质内容的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值