当前位置: 首页 > Web前端 > CSS

从一个现象理解CSS级联上下文

时间:2023-03-30 16:59:46 CSS

现象。在实现Loading组件的时候,不知道大家有没有遇到过以下问题:一、看正常情况:如果尝试给Loading组件下面的图片添加样式position:relative;z-index:1,会出现如下情况:这里的Loading组件是使用opacity和transition实现的(参考Taro的实现),上面实现的具体代码可以看这里;Loadingbox通过设置opacity显示从0到1的过渡,中间通过transition实现渐变效果;//opacity从0过渡到1,transition实现渐变??

...省略代码
可以发现当页面上有其他定位元素时,部分Loading框显示异常。该异常在opacity小于1时被遮挡,opacity等于1时完全显示。从本质上讲,如果要解决这个问题,其实有很多方法:比如去掉定位元素Style,如以上情况,可以去掉图片position:relative的样式;z-索引:1;但显然,这是不可取的,是治标不治本;或者修改Loading框的样式,比如去掉tansition的渐变样式,但是这种方法导致Loading框的外观,失去了渐变的效果;要想出更好的解决办法,就要看清现象的本质;其实这个问题的原因是opacity的css属性让元素产生了Cascadingcontext;MDN文档中提到,在某些场景下,会产生级联上下文,当opacity小于1时,也会产生;在生成级联上下文的dom节点中,其内部的级联顺序不会影响外部元素;所以在显示Loading组件的过程中,由于它的opacity是逐渐从0变成1的,所以:当opacity小于1时,在id为toast的div中形成一个stackingcontext,内部的loadingstyle会不影响外部因素,所以z-index为1的img-wrap会覆盖Loading组件;当opacity大于1时,id为toast的div不形成stackingcontext,所以z-index为1的img-wrap会被Loading组件的z-index覆盖:5000overlay;<样式>.loading{z-index:5000;位置:固定;顶部:30%;左:50%;}
??...省略代码明白这个问题的本质是级联上下文导致的,那么首先我们要掌握了级联上下文的原理,才能更好的解决这个现象;什么是CSS级联上下文在介绍级联上下文的概念之前,首先要说明的是,HTML中每个元素的位置都有一个三维的概念,即x、y、z的位置值轴表示元素的位置;其中,z轴方向的HTML元素具有堆叠关系,元素会按照一定的优先级进行渲染;这里,元素在z轴方向的堆叠顺序Priority是基于堆叠上下文的概念实现的;和BFC一样,当你第一次看到堆栈上下文时,这个概念感觉很抽象。在张新旭的文章中,用了一个官方来形容stackingcontext。同级官员用层层叠叠来形容,这个概念更容易理解;在本文中,我将使用我自己的另一个比喻来重新解释级联上下文。一个stackingcontext是按照stackingorder的规则进行排序的,所以stackingcontext可以比作一个装有卡片的盒子,盒子里的卡片是按照一定的堆放规则排序的;例如,在下面的HTML代码中,各个元素之间的级联关系可以形象地表示为:div1childdiv3堆叠顺序和stackinglevel那么对于同一个stackingcontext,元素的堆叠顺序是怎样的呢?在描述堆叠顺序之前,先介绍一下堆叠层级:参考CSS规范中的描述:在同一个堆叠上下文中,每个元素都有一个堆叠层级,堆叠层级用一个整数表示,可以是负值,它描述了元素在z轴上相对于当前堆叠上下文中其他元素的位置。具有较高堆叠级别的元素始终位于具有较低堆叠级别的元素之前。级联层级的元素会按照DOM流中的先后顺序进行布局,即最后来者的原则;需要注意的是,级联层级和CSS的z-index不能混淆。z-index只影响定位元素和flexbox子元素的级联层级;级联级别的所有元素都存在。堆叠顺序(stackingorder)表示元素堆叠时的垂直堆叠顺序;上面说的层叠上下文和层叠层级其实是概念,层叠顺序是一个特定的规则;在每个层叠上下文中,元素会按照如下(1为最低层,7为最高层)进行层叠:第1层,生成层叠上下文的元素的背景和边框;Layer2,负级联级别的后代级联上下文;Layer3,正常流中,非行Inline,非定位子元素;第4层,非定位浮动子元素;第5层,常规流、行内、非定位子元素,包括行内表(inline-table)和行内块(inline-block);第6层,堆叠级别为0的后代堆叠上下文和堆叠级别为0的定位子元素(z-index为0或auto);第7层,具有正堆叠级别的后代堆叠上下文;在Layer6中,可以解释为什么一个普通的元素一旦有了stackingcontext,它的stackingorder就会变高;因为一个元素有了堆叠上下文后,如果不是定位元素,那么它就属于堆叠级别为0的后代堆叠上下文;如何生成级联上下文满足以下任一条件的元素将自动创建级联上下文(引用自MDN):文档根元素();position值为absolute(绝对定位)或relative(相对定位)且z-index值为非auto的元素;position值为fixed(固定定位)或sticky(粘性定位)的元素;flex(弹性盒)容器的子元素,且z-index值不是auto;一个网格(grid)容器的子元素,并且z-index值不是auto;opacity属性值小于1的元素;mix-blend-mode属性值不正常的元素;以下任何一个属性值不为none的元素:transform,filter,perspective,clip-path,mask/mask-image/mask-border;isolation属性值为isolate的元素;-webkit-overflow-scrolling属性值为touch的元素;will-change值设置任意属性且该属性处于非初始值在以下情况下创建堆叠上下文的元素;contain属性值为layout、paint或包含其中之一的复合值(例如contain:strict、contain:content)的元素一些例子这里我选择两个我认为比较重要的点来说明:有层叠上下文的元素比普通元素有更高的层叠一般情况下,div1和div2不构成级联上下文。按照后来者的原则,div2会覆盖在div1之上。如下图左侧所示;当div1添加filter的css属性时:blur(0px);此时div1满足产生堆叠上下文的条件,堆叠层级高于普通元素,如下图右侧所示;当不同的堆叠顺序比较元素时不关心DOM中元素的层级关系父元素不产生栈上下文,所以父子元素在同一个栈上下文中,所以按照层叠顺序order,child属于堆叠层次为负的后代堆叠上下文,而parent属于正常流,非内联,非定位的子元素,所以parent应该在child之上,如下图左侧;当parent添加了opacity:0.9属性后,就形成了一个堆叠上下文。孩子在这个堆叠上下文中。按照堆叠顺序,高于生成堆叠上下文的元素的层级。因此,child在parent之上,如下图右侧所示;到了原题,了解了级联上下文的一些规则后,回到原题,如何更好的解决Loading组件中opacity的css属性,让元素生成级联上下文;//不透明度从0转换为1,transition实现渐变??...省略代码我觉得既然toast节点生成了级联上下文,loading节点也有position:fixed的css属性;z-index:5000;,Loading组件的最终目的是让组件层级更高,所以不妨增加toast节点的级联层级,修改如下://opacitytransitionsfrom0to1,transition实现渐变...省略代码Epilogue通过上面的案例和分析,理解了元素之间的堆叠关系不仅受z-index控制,还有规则堆叠上下文和堆叠顺序也会引起元素堆叠的变化。熟练使用规则,理解层叠上下文的原理,将有助于我们更好地维护页面中元素的层级关系;这篇文章是站在巨人的肩膀上,根据自己的理解和遇到的问题总结出来的。欢迎批评指正;参考深入理解CSS中的级联上下文和级联顺序CSScascadingorder探索MDN关于级联上下文css规范的文档