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

(翻译)CSS定位和堆叠上下文(Stackingcontext)

时间:2023-03-31 11:07:26 CSS

当你使用定位的时候,你会遇到这样的情况,一个定位元素即使设置到更高一层也无法覆盖另一个定位元素?通过了解堆栈上下文,您可以更好地构建您的应用程序。了解渲染过程和级联顺序当浏览器将HTML解析为DOM结构时,它还会创建另一种树结构-渲染树。它被渲染后,就成为了用户看到的视图,同时也决定了浏览器绘制HTML元素的顺序。这个顺序很重要,因为越晚渲染的元素,它的显示顺序就越高,有可能会覆盖前面的元素。在没有定位的情况下,渲染顺序由HTML元素的顺序决定,例如下面的HTML结构:

one
two
three
它们的堆叠顺序如下图所示,作者使用了一些负边距来强制元素覆盖,但没有使用定位。元素渲染得越靠后,显示得越近。当您使用定位时,此行为会发生变化。浏览器先绘制没有定位的元素,然后绘制有定位的元素。默认情况下,使用定位的元素会显示在不使用定位的元素之前。下图中,为前两个元素设置定位position:relative,它们的显示顺序会变成最前面,覆盖第三个没有定位的元素(position属性默认值为static,即not定位),即使它在HTML结构中的顺序没有改变。请注意,在这些定位元素中,第二个元素仍然显示在第一个元素的前面。首先定位元素会显示在普通元素的前面,然后根据HTML结构中的顺序来决定定位元素的显示,也就是显示在前面。什么是级联上下文?由浏览器绘制的一个或多个元素组成的DOM树形成级联上下文。当你在定位元素上设置z-index属性时(position是relative,absolute,fixed,sticky),这个元素会创建一个新的层叠上下文,并成为这个层叠上下文的根元素。此根元素的所有子元素都是此堆叠上下文的一部分。堆叠上下文的子元素都在其中绘制,因此堆叠上下文外部的元素无法在堆叠上下文内部的子元素之间设置它们的位置。也就是说,外层元素C不能在堆叠上下文的子元素A和B的中间。同理,当一个元素C被设置为覆盖另一个元素D时,D元素内部的子元素不能位于元素C之上。举个例子来说明:onenested
two
three
上面的HTML结构包含三个具有类名box的元素,其中两个将使用定位,并将其z-index值设置为1。第一个.box元素中的.absolute子元素将使用定位并将z-index值设置为100;即使.abosolute的z-index值很高,它仍然会被第二个.box元素覆盖,因为它的父元素——第一个.box元素的堆叠上下文在第二个.box元素的堆叠上下文之前。框元素。下面是CSS代码body{margin:40px;}.box{display:inline-block;宽度:200px;行高:200px;文本对齐:居中;边框:2px纯黑色;背景色:#ea5;边距-left:-60px;//让后面的元素覆盖其他元素vertical-align:top;}.one{margin-left:0;}.two{margin-top:30px;}.three{顶部边距:60px;}.positioned{//每个定位元素都会创建一个z-index为1的堆叠上下文position:relative;背景色:#5ae;z-索引:1;}.absolute{位置:绝对;顶部:1em;右:1em;高度:2em;背景色:#fff;边框:2px虚线#888;z-指数:100;//z-index属性只控制自身在当前层叠上下文中的位置line-height:initial;padding:1em;}因为第一个.box元素被第二个.box元素覆盖,属于堆叠上下文的根元素,其子元素,绝对定位的.positioned元素不会显示在两个.box的前面元素,即使孩子的z-index很高。将z-index属性添加到定位元素是创建堆叠上下文的最常见方法,但还有其他属性也可以创建堆叠上下文。例如:设置透明度小于1,transform、filter、attributes等都会创建层叠上下文。这些属性会影响元素及其子元素,因此它们具有相同的堆叠上下文属性。文档根(html)元素还为整个页面创建了一个顶级堆栈上下文。当然,还有其他的属性也可以创建堆叠上下文,但我们仍然很少使用它们。有兴趣的可以参考MDN。堆叠上下文中的元素按以下顺序显示,从后到前:堆叠上下文的根元素定位为负数的元素z-index值(其子元素也相同)未定位的元素(位置:static是默认值,相当于没有定位)被定位的元素有z-index:auto(它的子元素也一样)被定位的元素有一个正的z-index值(它的子元素也一样))使用变量来跟踪z-index属性滥用z-index属性会使样式文件难以维护,没有清晰的层级顺序,很容易在组件之间移动陷入“z-index”战争.如果没有规范要求,开发者可能会添加一个模态框组件,因为他们担心模态框组件会被其他组件覆盖,所以给它添加了一个相当高的级别,比如“999999”。当同一个页面多次出现同样的情况时,你不知道要为新组件设置多少层级。如果你使用CSS预处理器,比如SASS或LESS,或者你需要让兼容的浏览器支持CSS变量,那么你可以优雅地解决这个问题。将所有z-index属性值存储在一个变量中,全部存储在一个地方。通过这种方式,您只需快速浏览一下就可以看到谁在谁面前展示:--z-loading-indicator:100;--z-nav-menu:200;--z-dropdown-menu:300;--z-模态背景:400;--z-modal-body:410;使用10或100的升序,因此您可以轻松地插入一些您希望出现在其他元素前面的z-index。如果你发现你设置了z-index属性的元素没有按照你想要的方式显示,你应该查看DOM结构,找到当前堆叠上下文的根元素,并设置更高的z-index属性来提升或降低上下文的整个堆栈层次结构。开发中需要注意的是,一个级联上下文中可能嵌套了多个级联上下文。当页面变得复杂时,通常很难看出当前组件属于哪个堆叠上下文。所以在创建层上下文时要小心。除非有特定原因,否则尽量不要创建级联上下文。尤其是在构建大型应用程序时。尽量将模态框等定位元素放在DOM的最高层,比如标签的前面,这样就不用担心可能的外部级联上下文。一些开发人员为页面上的许多元素设置定位。好吧,不应该这样,您使用的定位元素越多,页面就会变得越复杂,并且越难调试。如果你经常使用定位元素,现在是正确处理它的时候了。构建页面布局的方式非常重要,当您可以使用其他方法完成布局时,最好使用这些方法而不是定位。如果你能利用文档流(Documentflow)的特性为你实现布局,而不是直接使用定位,浏览器会帮你考虑一些可能的边缘情况。请记住使用定位将元素从标准文档流中取出。通常,仅当您需要将一个元素放置在另一个元素之上时才考虑定位。参考资料:《CSS in Depth》KeithJ.Grant