不知道大家有没有听过 CSS 层叠上下文这个名词,我最近听到这个词的时候,一脸懵逼,压根就没有听说过这个名词。出于好奇心,我就在MDN里查阅了这个名词好好研究了一番,它在MDN里是这样描述的:
如果你也对层叠上下文的知识不太清楚,那么系好安全带,咱们准备出发了。
正文
层叠上下文英语全称为stacking context,实际上平时你在书写 CSS 时,大多数情况下你是感受不到它的存在,因此你不知道这个知识点也是一件很正常的事情。在MDN文档里它是这样描述的
那么,这个层叠上下文究竟说了什么内容呢? 说起来也简单,就是元素在页面上的层叠顺序,会受到它的层叠上下文所影响。 层叠上下文定义了元素如何影响其他元素的层叠顺序,以及元素在页面上的显示顺序。 我们可以把它总结为三点:
- 层叠上下文可以包含在其他层叠上下文中,并且一起创建一个层叠上下文的层级。
- 每个层叠上下文都完全独立于它的兄弟元素:当处理层叠时只考虑子元素。
- 每个层叠上下文都是自包含的:当一个元素的内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层叠。
让我们从最简单的 case 开始看。
html
<body>
<div class="container">
<div class="item"></div>
</div>
</body>
css
.container{
width: 500px;
height: 300px;
background-color: skyblue;
position: relative;
}
.item{
width: 50%;
height: 50%;
background-color: red;
position: absolute;
top: 20px;
left: 20px;
}
请仔细阅读上面的代码,然后你认为 div.item 这个盒子的层叠顺序是什么? 相信看完上面的描述,你能够很自信的回答这个简单的问题,div.item 盒子的层叠顺序是在其父元素 .container 之上。 这个答案确实是没有问题的,但是如果我追问你是怎么得到这个答案的,我猜不了解层叠上下文的你大概率会说,因为它的父元素 div.container 的 position 为 relative,所以 div.item 的层叠顺序是在其父元素之上。 这个答案实际上是不准确的。正确的答案应该是,div.item 的层叠顺序是根据它的层叠上下文来计算的,而这里层叠上下文的大小,正是这个元素最近的祖先层叠上下文元素。这是什么意思呢?
.item
元素的层叠顺序确实受其最近的层叠上下文(即其父元素.container
)的影响。然而,对于.item
来说,其层叠顺序不仅仅因为.container
的position: relative
而在其之上,而是因为.item
自身的position: absolute
使其创建了一个新的层叠上下文。当一个元素的定位类型为
absolute
或fixed
,或者它具有transform
,opacity
,mix-blend-mode
,filter
,clip-path
,mask
,perspective
,isolation
属性设置为非默认值时,它会创建一个新的层叠上下文。.item
使用了position: absolute
,因此它创建了自己的层叠上下文。然而,在这个例子中,
.item
和.container
都没有显式地指定z-index
值。在没有z-index
的情况下,元素的层叠顺序主要由它们在文档流中的出现顺序决定。因为.item
在.container
内部的HTML源码中出现在.container
的结尾附近,所以在默认情况下,它将位于.container
的其他内容之上,只要它没有被其他具有更高z-index
或者在它之后出现并创建层叠上下文的元素覆盖。虽然
.item
的层叠顺序是在.container
之上,但这主要是因为.item
的定位���式和在源码中的位置,而不是直接因为.container
的position: relative
。如果.container
没有position: relative
,.item
的position: absolute
也会相对于 body 或者下一个最近的具有定位属性的祖先元素创建层叠上下文。但是,.container
的position: relative
确保了.item
相对于.container
进行定位,而不是相对于 body 或其他元素。
因此正如我前面所说,很多时候你都感受不到层叠上下文的存在。
层叠上下文分为几种,分别是:
- 文档根元素(
<html>
); - position 值为 absolute(绝对定位)或 relative(相对定位)且 z-index 值不为 auto 的元素;
- position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);
- flex (flex) 容器的子元素,且 z-index 值不为 auto;
- grid (grid) 容器的子元素,且 z-index 值不为 auto;
- opacity 属性值小于 1 的元素(参见 the specification for opacity);
- mix-blend-mode 属性值不为 normal 的元素;
- 以下任意属性值不为 none 的元素:
- transform
- filter
- backdrop-filter
- perspective
- clip-path
- mask / mask-image / mask-border
- isolation 属性值为 isolate 的元素;
- will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章);
- contain 属性值为 layout、paint 或包含它们其中之一的合成值(比如 contain: strict、contain: content)的元素。
层叠上下文的层级关系
层叠上下文之间存在层级关系,层叠上下文由内向外,层叠顺序依次降低。这意味着内层的层叠上下文会覆盖外层的层叠上下文。
层叠上下文的应用场景
了解层叠上下文的概念对于解决实际开发中的布局问题非常有帮助。以下是一些层叠上下文在实战中的应用场景:
- z-index 值的影响:通过设置不同的 z-index 值,可以控制元素的层叠顺序。
- 定位元素与层叠上下文:了解定位元素如何创建层叠上下文,可以帮助我们更好地控制元素的显示顺序。
- flex 元素与层叠上下文:使用 flex 布局时,了解层叠上下文可以让我们更好地控制子元素的层叠顺序。
- grid 元素与层叠上下文:使用 grid 布局时,了解层叠上下文可以让我们更好地控制子元素的层叠顺序。
总结
层叠上下文是 CSS 布局中的一个重要概念,它定义了元素在页面上的层叠顺序。通过深入理解层叠上下文的工作原理,我们可以更有效地使用 CSS 属性,实现复杂而优雅的页面布局。记住,每个元素都存在于一个层叠上下文中,而这个上下文决定了元素在页面上的显示顺序。 在实际开发中,了解层叠上下文的概念对于解决布局问题非常有帮助。通过实践和不断学习,我们可以更好地掌握层叠上下文的应用技巧,提高我们的 CSS 布局能力。