堆叠上下文
本文试着先解释一下堆叠顺序是什么,在引入堆叠上下文。
MDN上这样解释堆叠上下文:
层叠上下文是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z轴上延伸,HTML元素依据其自身属性按照优先级顺序占用层叠上下文的空间。
平时我们浏览网页时,可以理解为从网页的正视图方向观看,理解堆叠上下文时,我们试着从侧视图的方向理解。方方老师说CSS的一个很重要的学习方法就是实验法,本文试着将所有的结论都有实验的依据。(祝福我吧,希望可以不看回放。。。)
首先,我们先思考一下,border和background的先后关系:
<body> <div class="demo"></div> </body> <style> .demo{ width: 100px; height: 100px; border: 10px solid rgba(255,0,0,0.5); background: green; } </style>
效果图:
可见,background < border;接着,我们在父元素里加一个div,观察一下border和子元素div的关系:
<body> <div class="parent"> <div class="child"></div> </div> </body> <style> .parent{ width: 100px; height: 100px; border: 10px solid red; } .child{ width: 30px; height: 30px; background: blue; margin-left: -5px; } </style>
效果:
由此得出,border<子元素块级元素div,如果元素浮动起来呢?
<body> <div class="parent"> <div class="child"></div> <div class="float"></div> </div> </body> <style> .parent{ width: 100px; height: 100px; border: 10px solid red; } .child{ width: 30px; height: 30px; background: blue; } .float{ width: 40px; height: 40px; background: rgba(0,255,0,0.7); float: left; margin-top: -10px; } </style>
效果:
浮动元素在块级元素div之上,那么内联元素捏,是不是也会被浮动元素盖住?在上面的代码中加入span元素。
<span class="inline">你好</span> span{ margin-left: -10px; }
效果:
所以内联元素在浮动元素之上,到现在我们的顺序是这样的,background<border<div<float<inline(内联)。
在说浮动元素时,我们经常说这样一句话:浮动元素脱离文档流,还有一种元素也脱离文档流,那就是定位的元素,例如:相对/绝对定位。
<div class="relative"></div> span{ margin-left: -20px; } .relative{ width: 30px; height: 30px; background: orange; position: relative; margin-top: -15px; }
效果:
相对定位的元素将在浮动元素上面的内联元素盖住了,所以内联元素<相对定位元素。两个性质相同的元素,后出现的会覆盖先出现的元素,例如:
<div class="relative"></div> <div class="absolute"></div> .relative{ width: 30px; height: 30px; background: orange; position: absolute; } .absolute{ width: 40px; height: 40px; background: rgba(0,0,0,0.5); position: absolute; }
效果图:
黑色背景的div把黄色背景的覆盖住了,但是如果我们把黄色背景的z-index设置一个除了0和auto的正值,就会有改变:
给.relative类加上这样一句话:z-index: 1;效果如下:
当z-index的值为负数时,会出现在哪呢?
<div class="parent"> <div class="relative"></div> <div class="absolute"></div> </div> <style> .parent{ width: 100px; height: 100px; border: 10px solid red; position: relative; background: green; } .relative{ width: 30px; height: 30px; background: orange; position: absolute; left: 50px; } .absolute{ width: 40px; height: 40px; background: black; position: absolute; } </style>
现在的效果是:
当把黄色部分的设置z-index: -1时,同时把父子元素的背景设置为半透明的,效果变成了:
说明,当z-index的值为负数时,是在background的后面的;
综上,z-index<0 ==> background ==> border ==> div ==> 浮动元素 ==> 内联元素 ==> 定位元素 ==> z-index>0,以上8层。
如果我们把position: relative的父元素设置z-index: -1,会发现子元素中z-index: -1的元素跑到了background上面,但是在div的下面。
<div class="parent"> <div class="child"></div> <div class="relative"></div> <div class="absolute"></div> </div> <style> .parent{ width: 100px; height: 100px; border: 10px solid red; position: relative; background: rgba(0,255,0,0.5); z-index: 0; } .child{ width: 40px; height: 40px; background: rgba(30,30,230,0.5); } .relative{ width: 30px; height: 30px; background: orange; position: absolute; left: 30px; top: 10px; z-index: -1; } .absolute{ width: 40px; height: 40px; background: black; position: absolute; } </style>
效果:
这是为什么呢,我们就这样从堆叠顺序的介绍过渡到堆叠上下文的概念,不生硬对吧。。。
因为position: relative 和 z-index不为auto形成了堆叠上下文,所以,类relative这个元素应该在parent形成的堆叠上下文里面。
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"的元素