情况是这样的:
body {
margin: 0;
background: pink;
color: #fff;
}
.box {
margin-top: 20px;
background: red;
}
.bottom {
text-align: right;
background: green;
animation: animate 2s infinite alternate linear;
}
@keyframes animate {
from {
margin-top: 10px;
}
to {
margin-top: -40px;
}
}
<div class="box">
some content
</div>
<div class="bottom">
other content
</div>
发生了什么事?
如您所见,我们有两个div
,没有任何复杂的样式(简单的背景色)。我通过应用一个负的margin-top
,使第二个div
与第一个div
重叠。我希望看到一个margin-top
与另一个完全重叠,但事实并非如此。第二个div
在第一个div
的内容和背景之间滑动,它是一个 对我来说很奇怪
动画在这里没有任何作用,我只是用它来更好地显示行为。我们可以简单地添加负边距而不使用动画,我们将得到同样的结果:
一个二个一个一个
所以我的问题是: * 为什么会这样**
顺便说一句,我们都知道CSS中有一些棘手的问题,当我们第一次面对它们时,我们不会怀疑它们(如边缘塌陷,从正文到html的背景传播,空白问题等),但它们在某个地方得到了明确的解释,我希望找到一个官方资源,我可以清楚地了解这一点,不仅得到这样的东西 "也许这是因为...",* "我怀疑这与......有关","我认为这与......有关"*,等等。
我对此的看法/解释
我认为像文本这样的内容比背景和其他视觉样式更重要,所以当我们有重叠时,我们可能会将所有文本放在顶部,所有其他样式放在底部,我们决定每组内的顺序,然后打印结果。
下面是一个更复杂的示例:
body {
margin: 0;
background: pink;
color: #fff;
}
div {
font-size: 39px;
line-height: 28px;
margin-bottom: -20px;
font-weight: bold;
}
body :nth-child(1) {
background: red;
border:3px solid brown;
}
body :nth-child(2) {
background: blue;
border:3px solid yellow;
color: #000;
}
body :nth-child(3) {
background: green;
border:3px solid orange;
}
<div>
some content
</div>
<div>
other content
</div>
<div>
more content
</div>
我们可以清楚地看到,* 可视化堆栈 * 如下(从下到上):
- 第一个**div的样式(背景+边框)
- 第二个**div的样式(背景+边框)
- 第三个**div的样式(背景+边框)
- 第一个**div的文本内容
- 第二个**div的文本内容
- 第三个**div的文本内容
***重要提示:***在回答之前,请注意我不是在寻找解决这个问题的方法或如何避免这个问题。通过简单地添加position:relative
,行为消失了,我们可以使用z-index
来决定堆叠。我希望了解为什么会发生这样的事情。
- 第三个**div的文本内容
8条答案
按热度按时间h9vpoimq1#
警告:阅读以下信息可能会影响您的心理健康。
生成堆叠上下文(请参见z-index属性)的元素后代的绘制顺序为:
1.如果元素是根元素:
1.整个画布上元素的背景色。
1.元素的背景图像,位于整个画布上,锚定在原点,如果为根元素绘制该图像,则将使用该图像。
1.如果元素为
1.块、列表项或其他块等效物:
1.元素的背景色,除非它是根元素。
1.元素的背景图像,除非它是根元素。
1.元素的列规则。
1.元素的边框。
1.否则,如果元素是块级表:
1.表格背景(颜色,然后是图像),除非它是根元素。
1.列组背景(先颜色后图像)。
1.列背景(先颜色后图像)。
1.行组背景(颜色,然后是图像)。
1.行背景(颜色,然后图像)。
1.单元格背景(颜色,然后是图像)。
1.多列的单元格列规则。
1.所有表格边框(对于分隔边框,按树顺序排列)。
1.按z索引顺序(最负的在前)然后按树顺序堆叠由z索引为负(不包括0)的定位后代构成的上下文。
1.对于树顺序中的所有流入、未定位的块级后代:
1.如果元素是块、列表项或其他块等效项:
1.元素的背景色。
1.元素的背景图像。
1.元素的列规则。
1.元素的边框。
1.否则,元素为表:
1.表格背景(颜色,然后是图像)。
1.列组背景(先颜色后图像)。
1.列背景(先颜色后图像)。
1.行组背景(颜色,然后是图像)。
1.行背景(颜色,然后图像)。
1.单元格背景(颜色,然后是图像)。
1.单元格列规则(多列)。
1.所有表格边框(对于分隔边框,按树顺序排列)。
1.按树顺序排列的所有非定位浮动后代。对于其中的每一个,将元素视为创建了新的堆叠上下文,但任何定位后代和实际创建新堆叠上下文的后代都被视为父堆叠上下文的一部分,而不是此新堆叠上下文的一部分。
1.如果元素是生成堆栈上下文的内联元素,则:
1.对于元素所在的每个行框:
1.跳转到7.2.1,查找该行框中元素的框(按树顺序)。
1.否则:首先为元素,然后按树顺序为其所有流入的、未定位的块级后代:
1.如果元素是块层替换元素,则:原子地替换内容。
1.否则,对于该元素的每个行框:
1.对于作为该元素的子元素的每个框,在该行框中,按树顺序:
1.元素的背景色。
1.元素的背景图像。
1.元素的列规则。
1.元素的边框。
1.对于行内元素:
1.对于此行框中的所有流入元素、未定位元素、内联级别子元素,以及此行框上的元素内的所有连续文本,按树顺序:
1.如果这是一串文本,则:
1.影响元素文本的任何下划线,按应用下划线的元素的树顺序排列(最深元素的下划线(如果有)绘制在最上面,根元素的下划线(如果有)绘制在最下面)。
1.影响元素文本的任何上划线,按应用上划线的元素的树顺序排列(最深元素的上划线(如果有)绘制在最上面,根元素的上划线(如果有)绘制在最下面)。
1.案文
1.影响元素文本的任何贯穿线,按应用贯穿线的元素的树顺序排列(这样,最深元素的贯穿线(如果有)绘制在最上面,根元素的贯穿线(如果有)绘制在最下面)。
1.否则,跳至7.2.1中查找该元素
1.对于内联块和内联表元素:
1.对于其中的每一个,将元素视为创建了新的堆叠上下文,但任何定位的后代和实际创建新堆叠上下文的后代都被视为父堆叠上下文的一部分,而不是这个新堆叠上下文的一部分。
1.对于内嵌级替换元素:
1.原子地替换内容。
1.元素的轮廓(可选)(请参见下面的10)。
请注意,有些框可能是由行分割或Unicode双向算法生成的。
1.如果元素是块级的,则为元素的轮廓(可选)(请参见下面的10)。
1.所有定位、不透明度或变换后代,按树顺序分为以下类别:
1.所有使用'z-index:自动'或' z轴索引:0 ",按树顺序。对于具有" z-index:auto ",则将该元素视为创建了新的堆叠上下文,但任何定位的后代和实际创建新堆叠上下文的后代都应被视为父堆叠上下文的一部分,而不是这个新上下文。对于带有" z-index:"0"处理原子地生成的堆栈上下文。
1.所有不透明度小于1的不透明度后代(按树顺序)创建一个原子生成的堆叠上下文。
1.所有具有非none变换的变换后代,按树顺序创建一个原子生成的堆叠上下文。
1.将由z索引大于或等于1的定位后代构成的上下文按z索引顺序(最小的先)然后按树顺序堆叠。
现在,认真地参考w3c油漆订单文档
在第4.1点中,绘制了儿童背景
在第4.4点中,绘制儿童的边界。
当第4点完成时,代码片段的所有背景和边框都已绘制完毕
现在,在点7.2.1.5.1.1.3中,绘制了子对象的文本。
这就是你所看到的行为。
注意,改变这个行为很容易,我们可以激活第8.2点(设置不透明度),它会像你期望的那样绘制:
另一个片段,显示文档中的几个点:
请注意,步骤4中的所有边框和背景都是在步骤3之后、步骤5之前呈现的。但步骤4中的文本是步骤7,因此在步骤5中的文本之后呈现
一个二个一个一个
我不知道这算不算用例:这使得初始行为比由相对定位的元件设置的行为更自然
uqdfh47h2#
这个问题的答案并不是每个人都在挖掘。因为我们都坚信这是一种利用用户体验的东西,一种直观的东西。有人认为这可以带来任何CPU处理的好处吗?
浏览器渲染引擎不会完整地绘制一个元素,然后继续绘制下一个元素,因为我们有GPU技术。渲染引擎在不同的堆叠层中一个接一个地绘制元素,然后将这些元素移交给GPU,GPU将所有层光栅化为一个复合层,显示在屏幕上。
那么,图层是如何创建的呢?
为什么文本是画在一个单独的层以上的基础层?
现在让我们来看看我们遇到的魔术由于这一点。
***案例1:**当位置相对添加到第二个div时,它会得到一个新层,这个新层堆叠在基础层上,甚至堆叠在第一个div的文本层上。
***案例2:**应用不透明度时会发生同样的情况。
***案例3:**任何变换样式都会创建一个新图层。
***案例4:**这个很有趣。边距不为第二个div创建任何层,它是在第一个div绘制后绘制在基础div上的,所以它是在同一层上绘制在第一个div上的。第一个div上的文本在它自己的层上,该层堆叠在基础层上,所以GPU在第二个div的背景上栅格化文本。
pepwfjgg3#
这是因为等级制度......我会试着多解释一点......
就像您的示例一样,我们的层次结构如下所示:
所以,现在,如果你不传递
position: relative
,那么它将使用普通的HTML层次结构,而不检查div ...您已经在
.box
和.bottom
上进行了后台实现,因此在这种情况下,当您将margin-top
添加到.bottom
中时,则:.bottom
和.box
具有相同的水平层次位置,但.bottom
具有较大的垂直,因此将与.box
背景重叠.bottom content
和.box content
的位置大于.bottom
和.box
,因此将与它们中的每一个重叠.bottom content
将与.box content
重叠,因为垂直层次结构更大ttygqcqt4#
问这个问题的一种方式是:是否可以用不同的方式处理它,同时仍然管理CSS所需的不同特性,特别是float属性?
规范中所说的是,对于堆叠上下文(基本上是DOM树中被定位的部分的顶部块),您可以按照该顺序绘制元素:
1.堆叠上下文的顶部元素的背景
到现在还说得通,那你有
1.所有块级元素的所有背景和边界(基本上是显示的元素:块但未定位)在树中的顶部元素下。
1.然后是顶部元素下的所有树的所有浮动元素。
1.这步进了步骤2中的else,所以它不会真正干扰这个特定的用例。
1.然后是top元素下所有树的所有in-flow元素(或非浮动元素)(在7中不仅呈现文本,还呈现所有inline元素。如果inline元素有背景,它会掩盖后面的内容)。
这样做的"问题"是流入元素不是按照树的顺序呈现的。树中较低位置元素的背景可以先于树中较高位置的流入元素呈现。这个问题暗示的是,我们可能会看到类似于以下的内容:
1.以树顺序呈现所有块级元素的所有背景和边界以及流入元素。
这将以一种更直观的方式生成元素。那么为什么要将流入元素与其他元素分开呢?为什么第5步在第7步之前呢?很明显,如果你这样做,那么你的浮动元素就有问题了。它们必须放在流的其他元素之前,因为它们就是从流中取出的元素。所以第5步是有意义的。你需要在考虑非浮动元素之前先考虑浮动元素。
那么,如果在步骤4中对它们进行渲染会怎样呢?
1.所有背景和边界,然后是所有块级元素的浮动元素和非浮动元素。
你仍然有一个问题,因为浮动元素的预期。请看下面的代码片段:
你会看到浮动元素对块元素的高度没有任何影响,这是意料之中的,否则结果会很奇怪,完全不是浮动元素所期望的。所以如果上面块中的浮动元素在下面元素的背景之前渲染,那么背景将在浮动元素之上。所以渲染背景,然后浮动,那么树顺序中的in-flow也不起作用。在进入正常流之前,需要放置所有树的所有float元素。
所以你很大程度上被这种处理渲染的方式所困扰,这意味着你必须检查一个上下文中的所有元素来定位浮动元素,然后定位正常流的其余部分。它有一个奇怪的副作用,但考虑到CSS规范所期望的不同定位的复杂性,我不确定是否有其他方法可以做到这一点。
编辑:
我认为这种行为在规范中有明确规定,请看这里:www.example.comhttps://www.w3.org/TR/CSS2/visuren.html#floats
浮动的内容被堆叠,就像浮动生成了新的堆叠上下文一样,除了任何定位的元素和实际创建新堆叠上下文的元素参与浮动的父堆叠上下文。浮动可以覆盖正常流中的其他框(例如当浮动旁边的正常流框具有负边距时)。当这种情况发生时,浮动被呈现在未定位的流入块之前,但是在流入管线之后。
这就是我所演示的内容,也就是说,浮动元素应该与流入块重叠,并呈现在这些背景的前面。
insrf1ej5#
@vals的答案突出显示了规范中解释此行为的位置,但仅提供了80%的答案,因为我仍在寻找为什么?。由于此行为在某种程度上违反直觉,我尝试找到此行为应该是这样而不是像我预期的真实用例。
在做了大量的搜索之后,我得出了一个合乎逻辑的结论:一个好的Web开发人员应该了解规范中指定的任何内容,不应该给随机/意外行为留有空间,特别是当涉及到规范中很好地解释的行为,而不是浏览器特定的行为时。
因此,我们编写代码,我们面对 * 奇怪 * 的事情,我们学习它们,我们调整我们的代码...我们这样做,直到我们有一些工作如预期。
由于Web开发人员可以完全控制自己的开发,所以我问自己,是否有任何外部工具可能会影响他的CSS和他无法控制的网页渲染?
是的,其中一个是关于可访问性。我不是在说一个网站开发者应该遵循的准则,而是在一些网站上的一些小部件,允许你增加字体大小,改变对比度等,以帮助你更好地阅读内容。这种小部件可以在任何地方使用插件集成。
下面是一个简化的示例,用户可以增加字体大小,上述行为非常有用,因为它将保持文本内容在上面,因此我们可以轻松阅读:
在这段代码中,开发人员使用了
14px
的字体大小,这对某些人来说可能很难阅读,所以我们想增加它是合乎逻辑的。如果我们这样做,我们将有 * 奇怪 * 的行为,但如果不是这样,内容将被隐藏,因此我们无法阅读它!这种情况是作出这项决定的充分理由,正如我在问题中所说:在这种情况下,内容比后面的样式更重要,特别是当涉及到改变初始行为的外部工具时。
此处增加字体大小的目的是为了突出显示内容而不是背景或边框,这确认了绘制顺序应该是这样的,以便满足此要求。
ozxc1zmp6#
理解为什么的关键在于理解浏览器绘画层
昨天我问了same question并寻求为什么?
我的问题的第一个假设是:
there is an overlapping
但是我发现根本就有
no overlapping
,即使我们在视觉上感觉到了!!最好将其命名为
intersecting
我开始转变想法去相信这一点的那一刻是当我在MDN上读到这张表的时候:
没有新的堆叠上下文这一事实
确保元素已绘制在同一层上,即(层0),这意味着相交而非重叠,这就是要点。
浏览器想先完成所有背景??因为他知道
hgqdbh6s7#
需要注意的是,在这种情况下,每个div都有其高度,这取决于它的内容。让我们暂时假设结果高度为20 px。
那么如果你说第一个div有margin-top20 px,在第一个div之后声明的第二个div从第一个div结束的地方开始。
因此,第二个的初始位置是第一个的margin-top加上第一个的高度。假设得到40 px。
所以,第二个div的起始位置在这种情况下是40 px.当你说第二个div的margin-top是-15px时,初始位置是40 px-15 px.所以,如果你想让第二个div覆盖第一个div,你应该把margin-top设置为等于第一个div高度的负值.
arknldoa8#
发生的情况是,您有2个重叠的“框”需要在同一个z层(层0)上渲染。然而,在Introduction to the CSS basic box model中,解释边界区域时,它说:
当在框上设置了背景(
background-color
或background-image
)时,它将延伸到边界的外边缘(即,在z排序中延伸到边界下方)。我假设边界和内容都在“前台”。
所以,在同一层上绘制所有框的规范,加上在前景下面绘制背景的规范,我猜它会导致在所有前景下面绘制所有背景。
在每个“子层”内,重叠是根据HTML顺序进行的。
要理解为什么日志中的DIV位于同一层,应该读取The stacking context。
要“理解”为什么背景在前景之下,应该读Introduction to the CSS basic box model。