桌子与堆叠上下文

本文详细阐述了CSS中的堆叠顺序与堆叠上下文的概念,通过实例解释了不同元素如何根据其属性相互堆叠,以及如何利用这些原理解决前端布局问题。

桌子与堆叠上下文

  或许有人会问,桌子与堆叠上下文有什么关系?我想说一句很欠揍的话,它们没什么关系。
  那我为什么要取个这样的标题呢?因为你们都认识桌子,却不一定能认出来堆叠上下文。但是我如果问你什么是桌子,你怎么说?它并没有一个明确的定义,但是你看到一个东西,就可以知道它是不是桌子。同样的,你在mdn上搜索堆叠上下文(层叠上下文),你看到的是“文档中的层叠上下文由满足以下任意一个条件的元素形成”。由…形成,嗯。如果它出现了,你就知道这就是堆叠上下文,但是别人问你什么是堆叠上下文的时候,你怎么说?
  好了对标题的解释就到这里,我们进入正题。

堆叠顺序

  首先要了解的不是堆叠上下文,而是堆叠顺序。堆叠顺序是基础。
1. 如果你给一个元素加了border和background,那么它们会不会有层叠关系呢?答案是有的。如果你给border加一个半透明的颜色,你就会发现background是在border下边的。所以我们的第一个层叠顺序就出来了。background < border
2. 在div有嵌套的时候,谁在上边呢?答案是div在上边。你可以看这个示例,我们可以看见,class为child的div把parent的border给挡住了。由此我们可以知道div是在border上边的。也就是border < div
3. 那float元素呢?我们知道给元素加float之后它会浮起来,那它会浮到所有的元素上边吗?这里我们可以看到,如果给紫色的div加了float的话,本该在它下边的并且盖住了它20px的红色的div就跑到了它的后边。所以事实是加了float的元素会在正常的div上边。div < float
  但是这里有一点需要注意一些,浮动元素里边如果有文字的话,这个文字是不会比它外边的文字高的。具体可以看这里。
4. 了解一些前端历史的可能会知道,float元素的出现最初是为了图文混排的,就是让文字环绕着图片显示。而图片在显示的时候往往处于一个次要的位置,文字才是焦点。这里的文字,就包括了inline元素和inline-block元素等。这里我们给紫色的div加上display: inline-block之后,它就盖在了红色div的上方。所以我们知道float元素 < 内联元素
5. 再往后,position: absoluteposition: relative的元素都脱离了文档流,那它们和内联元素的层叠关系是什么样的呢?答案是绝对定位和相对定位的元素会优先于inline元素显示在用户面前。并且这绝对定位和相对定位对层叠顺序的影响相同。你可以自己试一试。所以内联元素 < 绝对/相对定位
6. 最后一个东西,z-index。z-index是一个神奇的属性。由上边的分析我们知道如果没有其他东西影响的话,默认的显示顺序由底层到最高层应该是background < border < div < float元素 < 内联元素 < 绝对/相对定位元素。但是z-index的加入,让这一切有了小小的意外。
  首先,z-index元素只对指定了position属性的元素有效。也就是说,它不影响其它的,只影响上边我们说的最高层级的东西。如果z-index为负,那么它会在background下边,如果为正,那么它在正常的绝对/相对定位元素上边,如果为0或者是auto,那么就在绝对/相对定位元素本该待的地方。
  但是,这是建立在你的父元素没有被定位的情况下。如果你的父元素被定位了并且z-index不等于auto的话,那么就算子元素的z-index为-1,它也会在父元素的background和border上边。你可以自己试一试

堆叠上下文

  好了,堆叠顺序解决了。现在可以讨论另一个问题了——堆叠上下文。
  堆叠上下文影响的只是z-index,在上边我们讨论堆叠顺序的时候,关于负的z-index有一个奇怪的现象,如果元素的爸爸加了position: relative并设置了不为auto的z-index值的时候,这个z-index为负的元素就会跑到background和border的上边。为什么呢?因为堆叠上下文。
  这里是MDN的原话:

文档中的层叠上下文由满足以下任意一个条件的元素形成:

根元素 (HTML),
z-index 值不为 "auto"的 绝对/相对定位,
一个 z-index 值不为 "auto"的 flex 项目 (flex item),即:父元素 display: flex|inline-flex,
opacity 属性值小于 1 的元素(参考 the specification for opacity),
transform 属性值不为 "none"的元素,
mix-blend-mode 属性值不为 "normal"的元素,
filter值不为“none”的元素,
perspective值不为“none”的元素,
isolation 属性被设置为 "isolate"的元素,
position: fixed
在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值(参考 这篇文章)
-webkit-overflow-scrolling 属性被设置 "touch"的元素

  其中第二条,就是我们上边接触到的了。
  还是拿桌子做一个不恰当的比喻吧!本来儿子元素和爸爸元素都在同一张桌子(根元素html)上,但是我们给父元素加了position: relative; z-index: -1;此时形成了层叠上下文,父元素就形成了一个单独的桌子,子元素在父元素这张桌子上。而background是这张桌子的颜色,border是这张桌子的边沿,子元素既然是在父元素这张桌子上,那就不会说把桌子挖开把子元素埋进去。唔,姑且这样理解吧!
  由此的话还有一些其它的东西也就比较好解释了。比如下边的代码
html:

<div class="parent1"><div class="child1"></div></div>
<div class="parent2"><div class="child2"></div></div>

css:

.parent1{
  width: 150px;
  height: 150px;
  background-color: green;
  position: relative;
  z-index: 1;
}
.child1{
  width: 100px;
  height: 100px;
  background-color: red;
  position: absolute;
  z-index: 2;
}
.parent2{
  width: 150px;
  height: 150px;
  background-color: orange;
  margin-top: -100px;
  position: relative;
  z-index: 1;
}
.child2{
  width: 100px;
  height: 100px;
  background-color: blue;
  position: absolute;
  z-index: 0;
}

  我们可以看到,parent1和parent2的z-index是相等的,parent2把parent1覆盖了。child1的z-index大于child2的z-index,child2依然把child1覆盖了。为什么?
如果你知道一个常识性的知识点,并且联想到我的桌子理论,那就很容易解释了。
  这个常识性的知识点是,如果两个元素层级关系相同,那么写在后边的会覆盖写在前边的。这个我相信所有了解过css的都深有体会。那么现在的结果就是,parent2在parent1后边出现,所以parent2理所当然的在parent1前边。现在还有一个问题,为什么child1的z-index大于child2的z-index,但是child2会覆盖child1呢?
  答案也很简单。想想摞在一起的桌子。html是一张桌子,加了定位和z-index的几个元素都是单独的桌子。html上边比较一下parent1和parent2看谁先摞上去谁后摞上去。答案是parent1先。parent1里边的元素又开始比较了,看是child1先摞上去还是其它的元素先上去,答案是没有其它的元素,只有一个child1,所以先把child1给压上去了。这才到了parent2,以及parent2里边的child2。因为child1和child2根本就不是一张桌子上的东西,所以它们并没有可比性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值