当重叠时,为什么相邻元素的背景不包含内容?

时间:2018-02-11 11:42:33

标签: html css css3 background overlap

情况如下:

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没有任何复杂的样式(只是背景颜色)。我通过应用否定div使第二个margin-top与第一个div重叠。我希望看到一个完全重叠,但事实并非如此。第二个body { margin: 0; background: pink; color: #fff; } .box { margin-top: 20px; background: red; } .bottom { margin-top:-10px; text-align: right; background: green; }在第一个内容和背景之间滑动,这对我来说是一个奇怪的行为。

这里的动画无关,我只是用它来更好地展示行为。我们可以简单地在没有动画的情况下添加负边距,我们也会有同样的事情:

<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>
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;
}

所以我的问题是:为什么会出现这种行为?

顺便说一句,我们都知道CSS有一些棘手的事情我们在第一次遇到它们时并不怀疑(比如边缘折叠,从身体到html的背景传播,白空间问题等等)。 ..)但他们在某处清楚地解释了,我希望找到一个官方资源,我可以清楚地理解这一点,而不仅仅是得到像“这可能发生的事情因为......”“我怀疑这与...相关......“”我认为它与......“等等有关。


我对此的看法/解释

我认为像文本这样的内容比背景和其他视觉样式更重要,所以当我们有重叠时,我们将所有文本放在顶部而所有其他样式放在底部,我们决定每个组内的顺序然后我们打印结果。

这是一个更复杂的例子:

<div>
  some content
</div>
<div>
  other content
</div>
<div>
  more content
</div>
position:relative

我们可以清楚地看到视觉堆栈如下(从下到上):

  • 第一个 div(背景+边框)
  • 的样式
  • 第二 div(背景+边框)
  • 的样式
  • 第三 div(背景+边框)
  • 的样式
  • 第一个 div
  • 的文字内容
  • 第二 div
  • 的文字内容
  • 第三 div
  • 的文字内容

重要提示: 在回答之前,请注意我不是要找到解决方法或如何避免这种情况。只需添加z-index,行为就会消失,我们可以使用{ "_id" : "Romeo and Juliet", "acts" : [ { "title" : "ACT I", "scenes" : [ { "title" : "SCENE I. Verona. A public place.", "action" : [ { "character" : "SAMPSON", "says" : [ "Gregory, o' my word, we'll not carry coals." ] }, { "character" : "GREGORY", "says" : [ "No, for then we should be colliers." ] }, // ... { "character" : "GREGORY", "says" : [ "To move is to stir; and to be valiant is to stand:", "therefore, if thou art moved, thou runn'st away." ] }, { "character" : "SAMPSON", "says" : [ "A dog of that house shall move me to stand: I will", "take the wall of any man or maid of Montague's." ] }, { "character" : "GREGORY", "says" : [ "That shows thee a weak slave; for the weakest goes", "to the wall." ] }, // ... }, // ... ] }, // ... ]} 来决定堆叠。我希望了解为什么会发生这种情况。

7 个答案:

答案 0 :(得分:28)

警告:阅读以下信息可能会影响您的心理健康。

  

生成堆叠上下文的元素的后代的绘制顺序(请参阅z-index属性)是:

     
      
  1. 如果元素是根元素:      
        
    1. 整个画布上元素的背景颜色。
    2.   
    3. 元素的背景图像,在整个画布上,锚定在原点上,如果它是为根元素绘制的话。
    4.   
  2.   
  3. 如果元素是      
        
    • 块,列表项或其他等效块:      
          
      1. 元素的背景颜色,除非它是根元素。
      2.   
      3. 元素的背景图片,除非它是根元素。
      4.   
      5. 元素的列规则。
      6.   
      7. 元素的边界。
      8.   
    •   
    • 否则,如果元素是块级表:      
          
      1. 表格背景(颜色然后是图像),除非它是根元素。
      2.   
      3. 列组背景(颜色,然后是图像)。
      4.   
      5. 列背景(颜色然后是图像)。
      6.   
      7. 行组背景(颜色然后是图像)。
      8.   
      9. 行背景(颜色然后是图像)。
      10.   
      11. 单元格背景(颜色然后是图像)。
      12.   
      13. 多列的单元格列规则。
      14.   
      15. 所有表格边框(按树状顺序分隔边框)。
      16.   
    •   
  4.   
  5. 堆叠由z-index顺序为负z-索引(不包括0)的定位后代形成的上下文(最多为负数)然后   树顺序。
  6.   
  7. 对于树中所有的流入,非定位,块级后代:      
        
    • 如果元素是块,列表项或其他等效块:      
          
      1. 元素的背景颜色。
      2.   
      3. 元素的背景图片。
      4.   
      5. 元素的列规则。
      6.   
      7. 元素的边界。
      8.   
    •   
    • 否则,元素是一个表:      
          
      1. 表背景(颜色然后是图像)。
      2.   
      3. 列组背景(颜色,然后是图像)。
      4.   
      5. 列背景(颜色然后是图像)。
      6.   
      7. 行组背景(颜色然后是图像)。
      8.   
      9. 行背景(颜色然后是图像)。
      10.   
      11. 单元格背景(颜色然后是图像)。
      12.   
      13. 单元格列规则(多列)。
      14.   
      15. 所有表格边框(按树状顺序分隔边框)。
      16.   
    •   
  8.   
  9. 所有未定位的浮动后代,按树顺序排列。对于其中的每一个,将元素视为创建新堆叠   上下文,但实际上任何定位的后代和后代   创建新的堆叠上下文被视为父级的一部分   堆叠上下文,而不是这个新的。
  10.   
  11. 如果元素是生成堆叠上下文的内联元素,则:      
        
    1. 对于元素所在的每个行框:      
          
      1. 跳转到7.2.1,查看该行框中元素的框(按树顺序)。
      2.   
    2.   
  12.   
  13. 否则:首先是元素,然后是树中顺序的所有流入,非定位,块级后代:

         
        
    1. 如果元素是块级替换元素,则:原子地替换内容。
    2.   
    3. 否则,对于该元素的每个行框:

           
          
      1. 对于该元素的子元素的每个框,在该行框中,按树顺序:

             
            
        1. 元素的背景颜色。
        2.   
        3. 元素的背景图片。
        4.   
        5. 元素的列规则。
        6.   
        7. 元素的边界。
        8.   
        9. 对于内联元素:      
              
          1. 对于此行框中的所有元素in-flow,non-located,inline-level子元素,以及   此行框中的元素,按树顺序:      
                
            1. 如果这是一段文字,那么:      
                  
              1. 任何影响元素文本的下划线,按应用下划线的元素的树顺序(最深的   元素的下划线(如果有的话)被绘制在最顶层和根部   元素的下划线(如果有的话)最底层绘制。)
              2.   
              3. 影响元素文本的任何覆盖,按照应用覆盖的元素的树顺序(这样最深的   元素的叠加(如果有的话)被绘制在最顶层和根   元素的叠加(如果有的话)是最底层的。)
              4.   
              5. 文字
              6.   
              7. 影响元素文本的任何直线操作,按照应用直通的元素的树顺序(这样最深的   element的直线(如果有的话)被涂在最上面和根部   元素的直线(如果有的话)是最底层的。)
              8.   
            2.   
            3. 否则,跳转到该元素的7.2.1
            4.   
          2.   
        10.   
        11. 对于内联块和内联表元素:      
              
          1. 对于其中的每一个,将元素视为创建新的堆叠上下文,但任何定位的后代和后代   实际上创建一个新的堆叠上下文被认为是一部分   父堆叠上下文,而不是新的上下文。
          2.   
        12.   
        13. 对于内联级替换元素:      
              
          1. 被替换的内容,原子地。
          2.   
        14.   
        15. 可选地,元素的轮廓(见下面的10)。
        16.         
              

          注意,某些框可能是通过行拆分或Unicode双向算法生成的。

            
            
      2.   
      3. 可选地,如果元素是块级的,则元素的轮廓(见下面的10)。

      4.   
    4.   
    5. 所有定位,不透明度或变换后代,按树的顺序分为以下类别:

           
          
      1. 所有定位的后代都带有&#39; z-index:auto&#39;或者&#39; z-index:0&#39;,按树顺序排列。对于那些使用&#39; z-index:auto&#39;的人,请将该元素视为   它创建了一个新的堆叠上下文,但任何定位的后代和   实际创建新堆叠上下文的后代应该是   被视为父堆叠上下文的一部分,而不是这个新的。对于   那些有&#39; z-index:0&#39;处理生成的堆叠上下文   原子。

      2.   
      3. 所有不透明度后代的不透明度小于1,按树顺序,创建一个原子生成的堆叠上下文。

      4.   
      5. 所有使用变换而非变换的后代以树的顺序创建以原子方式生成的堆叠上下文。
      6.   
    6.   
    7. 在z-index顺序(最小的第一个)中堆叠由z-indices大于或等于1的定位后代形成的上下文然后树   顺序。
    8.   

现在认真,请参阅the w3c paint order documentation

在第4.1点中,绘制了儿童的背景

在第4.4点中,儿童的边界被涂上了颜色。

当第4点完成后,您的代码段的所有背景和边框都已绘制

现在,在第7.2.1.5.1.1.3点中,儿童的文字被涂上了颜色。

这是您所看到的行为。

另请注意,很容易更改此行为。我们可以激活点8.2,(设置不透明度),它会像您预期的那样绘制:

&#13;
&#13;
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;
  opacity: 0.9999;
}

@keyframes animate {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: -40px;
  }
}
&#13;
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>
&#13;
&#13;
&#13;

另一个片段,在文档中显示了几点:

请注意,步骤4中的所有边框和背景都在步骤3之后和setp 5之前呈现。但步骤4中的文本是步骤7,因此在步骤5中的文本之后呈现

&#13;
&#13;
div {
  width: 200px;
  height: 100px;
  border: solid 10px;
  font-size: 40px;
}

.step3 {
  border-color: red;
  background-color: lightpink;
  z-index: -1;
  position: relative;
  margin-left: 10px;
}

.step41 {
  border-color: brown;
  background-color: yellow;
  margin-left: 30px;
  margin-top: -40px;
}

.step42 {
  border-color: blue;
  background-color: lightblue;
  margin-left: 50px;
  margin-top: -40px;
  color: red;
}

.step43 {
  border-color: green;
  background-color: lightgreen;
  margin-left: 160px;
  margin-top: -150px;
  color: crimson;
}

.step5 {
  float: left;
  background-color: white;
  margin-top: -30px;
}

div:hover {
  position: relative;
}
&#13;
<div class="step3">Step 3 negative zindex</div>
<div class="step41">step4 In flow, number 1</div>
<div class="step42">In flow, number 2</div>
<div class="step43">In flow, number 3</div>
<div class="step5">step 5 float</div>
&#13;
&#13;
&#13;

我不知道这是否算作一个用例:这个元素定位相对的初始行为更自然

&#13;
&#13;
div {
  width: 100px;
  height: 1.3em;
  border: solid 12px tomato;
  font-size: 18px;
}

div:hover {
  position: relative;
}
&#13;
<div>a long stretch of text overflowing to the other div</div>
<div></div>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

这是因为层次结构......我会尝试更多地解释一下......

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  margin-top:-10px;
  text-align: right;
  background: green;
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

就像你的例子一样,我们的层次结构如下:

.box
    .box content
.bottom
    .bottom content

所以,现在如果你没有传递position: relative,那么它将使用HTML的普通层次结构而不检查div ...

您已在.box.bottom实施了背景,因此在这种情况下,当您将margin-top添加到.bottom时,则:

  • .bottom.box具有相同的水平层次结构位置,但.bottom具有更大的垂直位置,因此将重叠.box背景
  • .bottom content.box content的排名大于.bottom.box,因此会重叠每个
  • 由于更大的垂直层次结构,
  • .bottom content将重叠.box content

答案 2 :(得分:3)

这个问题的答案远不是每个人都在挖掘。因为我们都认为这是一种无论如何都能充分利用用户体验的东西,这是一种直观的东西。有没有人认为这可以用于任何CPU处理好处?

浏览器渲染引擎不会完全绘制元素,然后继续绘制下一个元素,因为我们拥有GPU技术。渲染引擎将不同堆叠层中的元素一个接一个地绘制到GPU上,然后GPU将所有层光栅化为显示在屏幕上的复合层。

Browser rendered layers

  

那么,如何创建图层?

  • 渲染引擎绘制基础图层上的所有背景和边框。
  • 为已指定位置的元素创建新图层。该层堆叠在基础层上,以便GPU对其进行栅格化。当元素移动时,渲染引擎只告诉GPU移动图层,GPU完成剩下的工作。从绘画开销中节省了CPU。
  • 为指定了不透明度的元素创建新图层。当不透明度发生变化时,GPU会进行光栅化工作。
  • 同样为输入,按钮,画布,视频创建一个新层,可以导致CPU重复绘制的所有内容都作为新层转移到GPU。我们节省了很多CPU处理,对吗? :)
  • 拒绝为具有负边距的元素创建任何新图层:(。显然,浏览器不能为每个带边距的元素发布新图层,其中有很多。即使它有负边距,它也可能重叠或不重叠唯一可以确定的方法是查看渲染树。重点是什么?我们正在尝试保存处理,查看每个元素的渲染树都会毁掉它。
  • 为文本元素发布新图层。 GPU可以更有效地将文本光栅化到背景上,那么为什么要在基础层上用CPU绘制它?这是最初的问题。我想现在每个人都可以回答。
  

为什么在基础图层上方的单独图层上绘制文字?

  • CPU不需要在背景上绘制文本,CPU很高兴。
  • 当文本颜色或阴影发生变化时,CPU仅绘制文本图层,GPU会在背景上对其进行栅格化。
  • 当背景更改时,CPU仅绘制背景图层,GPU会在其上栅格化文本。
  • 当文本在固定的背景上滚动时,不需要绘画,CPU只会告诉GPU移动文本层,GPU会完成剩下的工作。
  • 还有很多......
  

现在让我们来看看我们遇到的魔法。

painting and rasterizing

  • 案例1:当将位置相对添加到第二个div时,它会获得一个新图层,这个新图层将堆叠在基础图层上,甚至覆盖在第一个div的文本图层上。
  • 案例2:应用不透明度时会发生同样的事情。
  • 案例3 :任何转换样式都会创建一个新图层。
  • 案例4:这个很有意思。边距不会为第二个div创建任何图层,它会在绘制第一个div后绘制在基础div上,因此它会绘制在同一图层上的第一个div上。第一个div上的文本位于它自己的图层上,该图层堆叠在基础层上,因此GPU在第二个div的背景上栅格化文本。

[来源:developers.google.com]

答案 3 :(得分:1)

@vals的答案强调了在规范中解释了这种行为但仅提供了80%的答案,因为我仍在寻找为什么?。由于这种行为在某种程度上违反直觉,我试图找到真实的用例,这种行为应该是这样,而不是像我预期的那样。

经过大量搜索后,我结束了逻辑结论,一个优秀的Web开发人员应该了解规范中指定的任何内容,不应该留下随机/意外行为的位置,尤其是当谈到行为时,规范很好地解释了,而不是浏览器特定的

所以我们编写代码,我们面对奇怪的事情,我们了解它们,我们调整代码......我们这样做,直到我们按预期工作。

由于Web开发人员可以完全控制他的开发,我问自己是否有任何外部工具可能会影响他的CSS以及他无法控制的网页呈现? / p>

是的,其中一个与辅助功能有关。我不是在谈论网络开发人员应该遵循的准则,而是关于某些网站中允许您增加字体大小的一些小部件,更改对比等,以帮助您更好地阅读内容。这种小部件可以使用附加组件集成到任何地方。

这是一个简化的示例,用户可以增加字体大小以及上述行为有用,因为它会将文本内容保留在上面,因此我们可以轻松阅读它:

$('button').click(function() {
   $('body').css('font-size','22px');
})
body {
 font-size:14px;
 max-width:500px;
}
section {
  height: 80px;
  background: red;
  padding:5px;
  border-top: 40px solid blue;
  color:#fff;
}
div {
  height:80px;
  background:url(https://lorempixel.com/g/400/400/) center/cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Make font bigger</button>
<section>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam cursus posuere dolor vel faucibus. Proin augue orci, tempor cursus erat aliquet, pellentesque suscipit odio. Sed eleifend diam in justo vehicula feugiat. In pretium, elit eu dapibus efficitur,
</section>
<section>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam cursus posuere dolor vel faucibus. Proin augue orci, tempor cursus erat aliquet, pellentesque suscipit odio. Sed eleifend diam in justo vehicula feugiat. In pretium, elit eu dapibus efficitur,
</section>
<div>
</div>

在此代码中,开发人员使用的字体大小等于14px,这对某些人来说很难阅读,因此我们想要增加它是合乎逻辑的。如果我们这样做,我们将会有奇怪的行为,但如果不是内容将被隐藏,那么我们就不能再阅读它了!

这种情况给出了这样的决定的充分理由,正如我在问题中所说:在这种情况下,内容比后面的样式更重要,特别是在涉及改变初始行为的外部工具时。

此处增加字体大小的意图是突出显示内容,而不是背景或边框,以确认绘画顺序应该是这样以满足此要求。

答案 4 :(得分:1)

提出这个问题的一种方法是:它可以以不同的方式处理,还能管理CSS所需的不同功能,尤其是浮动属性吗?

规范说的是,对于堆叠上下文(基本上是定位的DOM树的一部分的顶部块),您按顺序绘制元素:

  1. 堆叠上下文的顶部元素的背景
  2. z-index negative
  3. 的元素

    直到现在它才有意义,那么你有

    1. 所有块级元素的所有背景和边框 (基本上是显示:阻止但未定位的元素)在顶部元素下的树中。
    2. 然后是顶部元素下所有树的所有浮动元素。
    3. 此步骤来自步骤2中的其他内容,因此它并未真正干扰此特定情况。
    4. 然后在顶部元素下的所有树的所有流入元素(或非浮动元素)(它不仅仅是在7中呈现的文本,它是所有内联元素。如果你的内联元素有背景,它会掩盖背后的东西。
    5. &#34;问题&#34;这就是流入元素不按树的顺序呈现。可以在树中的流入元素上方之前呈现树中较低元素的背景。这个问题隐含的是我们期待的更像是:

      1. 按树顺序渲染所有块级元素的所有背景和边框以及in-flow元素。
      2. 这将以更直观的方式生成元素。那么为什么然后将流入元素与其余元素分开。为什么步骤7之前的步骤5?很明显,如果你这样做,那么你的浮动元素就会出现问题。它们必须放在流程的其余部分之前,因为它们是什么,从流程中取出的元素。所以第5步有意义,你需要在非浮动元素之前考虑浮动元素。

        那么,如果它们在步骤4中呈现,如下所示:

        1. 所有背景和边框,然后按树顺序浮动,然后浮动所有块级元素的非浮动元素。
        2. 由于浮动元素的预期,你仍然有问题。请参阅以下代码段:

          &#13;
          &#13;
          body {
            margin: 0;
            background: pink;
            color: #fff;
          }
          
          .box {
            margin-top: 20px;
            background: red;
          }
          
          .bottom {
            margin-top:-10px;
            text-align: left;
            background: green;
            
          }
          &#13;
          <div class="box">
            <span>some content some content some content some content some content some content some content some content some content some content</span>
          <span style="float: left; background: navy">
            floated content box<br>
            floated content box<br>
            floated content box<br>
            floated content box
            </span>
            
           
            
            
          </div>
          <div class="bottom">
            <span style="background-color:turquoise;">other content</span>
            <span style="float: left; background-color:bisque;">
            floated content bottom<br>
            floated content bottom<br>
            floated content bottom
            </span>
            
           
            
          </div>
          &#13;
          &#13;
          &#13;

          你会发现浮动元素对块元素的高度没有任何影响,这是预期的,否则结果会很奇怪,而不是所有的预期。浮动元素。因此,如果上部块中的浮动元素在下部元素的背景之前呈现,则背景将在浮动元素上方。因此渲染背景,然后浮动,然后以树顺序进行流入也不起作用。在进入正常流程之前,您需要放置所有树的所有浮动元素。

          所以你几乎坚持使用这种处理渲染的方式,这意味着你必须在一个上下文中检查所有元素以定位浮动元素,然后定位其余的正常流。它具有这种奇怪的副作用,但考虑到CSS规范所期望的不同定位的复杂性,我不确定是否有另一种方法可以做到。

          编辑:

          我认为这些行为在规范中有明确规定,请参见此处: https://www.w3.org/TR/CSS2/visuren.html#floats

            

          浮动的内容被堆叠,好像浮动产生了新的堆叠   上下文,除了任何定位的元素和元素   实际上创建新的堆叠上下文参与浮动的父级   堆叠上下文。浮动可以与正常流中的其他框重叠   (例如,当浮动旁边的正常流动框具有负边距时)。   发生这种情况时,浮动将呈现在非定位前面   流入块,但在流入内联后面。

          这正是我所说明的内容,这意味着它要求浮动元素重叠流入块,并在这样的背景前呈现。

答案 5 :(得分:-1)

重要的是要注意,对于这种情况,每个div由于其内容而具有其高度。 让我们说一下产生的高度是20px。

然后,如果你说第一个div将有margin-top:20px,那么在第一个div之后声明的第二个div从第一个div结束的地方开始。

所以,第二个的初始位置将是第一个的边缘 - 顶部加上第一个的高度。让我们说给出40px。

因此,对于这种情况,第二个的起始位置将是40px。当你说第二个div的margin-top是-15px时,初始位置将是40px-15px。 所以,如果你希望第二个与第一个重叠,你应该将margin-top设置为等于第一个的高度的负数。

答案 6 :(得分:-1)

会发生什么事情,你有两个重叠的盒子&#39;需要在同一z层(第0层)上渲染。但是,在Introduction to the CSS basic box model中,解释边界区域,它表示:

  

如果在框中设置了背景(background-colorbackground-image),它会延伸到边框的外边缘(即以z顺序在边框下方延伸)。

我认为边框和内容都在&#39;前景&#39;。

所以,在同一层上绘制所有框的规格,结合在前景下绘制背景的规格,我想这会导致所有背后的所有背景前景。

在每个子层内部&#39;重叠是根据HTML顺序。

要理解帖子中的DIV在同一图层上的原因,请阅读The stacking context

了解&#39;为什么背景幕在前景之下,应该阅读Introduction to the CSS basic box model

相关问题