当前位置: 首页 > 科技观察

抖音一方面:Z-index大的元素一定在小的元素之上吗?

时间:2023-03-18 18:50:27 科技观察

大家好,我是念念!在开始这篇文章之前,我先提两个面试真题:z-index值大的元素一定在值小的元素之上吗?如何实现父元素覆盖子元素?先公布答案:z-index不一定生效,也不一定在top有很大的值,主要看stackingcontext;为父元素设置大的z-index不能覆盖子元素,但是将子元素的z-index设置为负数即可满足要求。这两道题的考点是级联上下文,本文会解释原因。顾名思义,层叠上下文就是从三维的角度,通过不同层级的元素放置来判断最终的层叠关系。它通过属性z-index确定“级别”。如何让z-index生效z-index用于指定元素在z轴上的高度,值越大,越接近用户,越“上”。在使用的时候,你可能会觉得这个属性不是很听话:给元素设置的z-index好像没有生效,并没有像预期的那样在其他元素上运行。因为单独使用不生效,所以必须和positioning属性一起使用,即只对指定position属性的元素生效——只要不是默认值static即可,其他绝对,relative和fixed可以使z-index有效。如图1所示,在粉红色的父元素下,有两个绝对定位的子元素1和2,它们都没有设置z-index,它们的位置由top/left属性控制,因此重叠。可以看到2在1之上,因为两者都没有设置z-index,所以可以认为堆叠层级为0,同一层级的元素会按照在层中出现的先后顺序来决定堆叠结果HTML。如果我们想让1在2之上,如图2所示,我们可以给元素1加上z-index:1,不指定z-index的元素2的z-index仍然可以视为0,根据对于大小关系,元素1在元素2之上。到此为止,没有难度,只是大小比较。但在很多情况下,会发现级联结果并不能用简单的数值来解释:如图3所示,粉色背景下有两个子元素1和2,而在粉色背景下有一个子元素32、三个元素是绝对定位的,其中元素3的z-index值最大,但是压在了元素1之下。稍微修改一下,只去掉元素2的z-index。如图4,元素3再次出现并覆盖了元素1和2。理解这些问题需要理解堆叠上下文。什么是堆叠上下文?堆叠上下文听起来很抽象。你可以把它想象成一个三维空间,里面有很多平面。最大的堆栈上下文是由文档的根元素——html构成的:它和它的子元素构成了最大的堆栈上下文,也就是说我们写的所有代码都在根堆栈上下文中。stackingcontext包含多个平面,具体来说:每个z-index值构成一个平面,普通未定位的块级元素也是一个平面,浮动元素也是一个平面,正是这些平面构成了stackingcontext。此外,每个具有z-index值的元素还会与其子元素一起生成一个小的堆叠上下文。这个小的堆叠上下文像父级一样有多个平面。在处理这些上下文的时候,我们可以按照从小到大的顺序递归:先梳理出最小堆叠上下文中元素的顺序,拍一张照片——作为一个整体,然后与父级堆叠上下文中的其他元素进行比较.不知道大家有没有见过小吃街上的甲骨片:把面糊放在一个大平底锅里,在面糊上放上一只小虾米,最后盖上盖子夹紧,变成一个扁扁的小块,可以清楚的看到上面虾的模样。(截图来自网络)用来压平板的锅是级联上下文,面糊和虾是不同层次的HTML元素。它们在被压平之前以明确的从上到下的顺序排列,但最终都变成了一片薄薄的小饼干。这块小饼干可以放到更大的锅里,作为原料和其他材料一起继续做大饼干,但在大锅的眼里,这小饼干到底是面糊还是虾仁生的?放在上面,根本无所谓,因为现在是一个整体,只有讨论这块小饼干和其他食材放在第二个锅里的顺序才有意义。请记住,在这个模型中,层次判断非常简单。当我们面对一些难以判断的层次关系时,我们可以梳理出一个“级联上下文树”,这有点类似于dom树的结构。从小到大,将不同平面的元素堆叠在一个堆叠上下文中,压平,放入父级的堆叠上下文树中。下面会通过几个例子来加深理解,都附上了在线链接,可以点进去看看能不能解释一下最终的渲染结果:demo1,DOM的层级关系如下:container1:absolute:number1:absolutez-index:No.12:absolutez-index:2container2:absolute:No.3:absolutez-index:3虽然container1和container2都是绝对定位的,但是没有设置z-index,不形成堆叠上下文。所以只有根元素形成这个。元素1、2、3当然也构成了一个级联上下文,但是它们没有子元素,就不展开讨论了。下面例子形成的级联上下文树也如下:根级联上下文:1号:绝对z-index:12号:绝对z-index:23号:绝对z-index:3最后的级联关系不难判断,从下往上就是No.1-No.。2号3demo2在demo1的基础上稍作修改,增加了z-index,现在DOM的层级关系变为:container1:absolutez-index:4.No.1:absolutez-index:No.12:absolutez-index:2container2:absolutez-index:1.No.3:absolutez-index:3container1和container2都设置了z-index,加上根元素形成的stackingcontext,一共有三个。形成的级联上下文树如下:Rootcascadingcontext:No.3:absolutez-index:No.31:absolutez-index:No.12:absolutez-index:2container1:absolutez-index:4container2:absolutez-index:1首先看container1形成的stackingcontext。这时候不管自己的z-index是多少,组成层叠上下文的元素都是在当前上下文的最底层,后面是元素1和2。然后就是container2形成的层叠上下文,还有只有一个3号元素,所以没什么好说的。最后,还有根堆栈上下文。在它眼里,container1和container2是一个整体,container2在底部,container1在顶部。所以最终从下往上的顺序是:container2(3号)-container1(1号-2号)。demo3之前的容器在视觉上是不可见的,现在给它一个颜色。container2的z-index设置为0,现在DOM的层级关系变成:container1:absolute1#:absolutez-index:2container2:absolutez-index:02#:absolutez-index:-1现在可以了从下往上看是container1-container2-2#-1#。这个例子比较难理解。用堆叠上下文树分析它。有两个stackingcontext,一个是根元素形成的,一个是container2。Rootstackingcontext:number2:absolutez-index:-1container1:absolute1number:absolutez-index:2container2:absolutez-index:0在container2形成的stackingcontext中,只有一个元素2,即使它的z-index是负数,也会放在container2上面。正如我之前所说,构成堆叠上下文的元素始终位于当前堆叠上下文的底部。我们将它们两个压平,形成一个整体。在rootstackingcontext中,有container1、container2和number1三个元素,container1没有设置z-index,可以看成0,和container2同级。当层级相同时,根据在html中出现的顺序来判断,所以是container1-container2;1号的层级最高,所以最后一层是container1-container2-1。最后展开container2中的其他元素,得到最终的级联关系container1-container2(No.2)-No.1。stackingcontext的规律通过这三个例子,大家应该能清楚的感受到什么是stackingcontext。让我们总结一下他的规则:只有明确指定z-index(不是auto)值的定位元素才会产生堆叠上下文。在这个堆叠上下文中,内部元素层级都在它之上,即使它是负数。如果是没有指定z-index的定位元素(也就是auto),那么虽然不能形成层叠上下文,但是在比较层的时候和z-index:0是一样的。如果我们也把浮动元素也放进去,就可以得到一个完整的级联层级:这张图看着复杂,其实不用背,可以一个一个看:先看块级元素,大部分我们写的代码就是它,例如div,我们可以看到它们,因为块级元素在堆栈上下文的根元素之上。然后是浮动元素和文字,浮动本身就是为了实现环绕效果,所以浮动元素和文字是在同一层级的,这样才不会被遮挡。然后是定位元素。我们知道,如果不指定z-index,即当为auto时,会在浮动元素之上,在层级关系上其实相当于0;可以继续启动,z-index>0会在z-index=0上面。唯一要记住的是z-index<0,它的层级关系在块元素之下,根元素之上形成堆叠上下文。其中,当多个堆叠层次相同的元素重叠时,根据它们在html中出现的先后顺序来确定堆叠上下关系,后出现的在最上面。CSS3的新特性除了定位z-index元素外,CSS3还提供了另一种生成堆叠上下文的方法。特殊的就不一一列举了,意义不大。开发中可能会用到:灵活布局的children(父元素display:flex|inline-flex),z-index不是auto。不透明度为1以外的元素。转换非无元素。过滤不是无的元素。这些可以生成层叠上下文,flex子元素也可以使用z-index来更精确的设置level。其他三个设置z-index不会生效,但在比较层次关系时会被视为z-index:0。结论级联上下文和z-index这两个概念是密不可分的。一个堆叠上下文由多个平面组成,这些平面由具有z-index属性的元素组成;具有z-index属性的元素形成子堆叠上下文。当然这里的z-index一定要有效设置。以前是指定位元素——position是absolute/relative等,现在也可以是flex的子元素。在比较复杂元素的层叠顺序时,主要需要梳理出一棵层叠上下文树,而一个元素的层叠层次只有在当前层叠上下文中才有意义。回到前两个问题,答案不难理解。具有大z-index的元素不一定位于小元素之上。因为不一定生效,通常需要是定位元素才会生效。CSS3之后,弹性元素的子元素也可以生效;z-index生效后,并不是简单的大小比较,因为这个值只有在当前级联上下文中才有意义。要实现父元素覆盖子元素,给父元素设置大的z-index是没有用的。因为这样他就成为了一个层叠上下文的根元素,无论子元素怎么设置,都会在层叠上下文的根元素之上。正确的解决方法是将子元素的z-index设置为负数,这样父元素就是块级元素,z-index<0的子元素就会在块级元素之下,并且可以达到我们想要的效果。

猜你喜欢