为什么不顶部:0相对于身体的绝对定位元素?

时间:2015-11-08 14:02:18

标签: html css css-position specifications

您可以在下面的代码中看到h1向下推动身体,绝对定位的块.absolute不会粘在顶部。但是您也可以看到同一个块粘贴在其父.wrapper的顶部。为什么呢?

我不是在问这个伎俩;我知道如何,例如填充而不是边距到h1,或clearfix到父级等等。

我只对一件事情感兴趣:为什么h1的保证金会推动body,但却没有推倒.wrapper

body {
  position: relative;
  margin: 0;
  padding: 0;
  overflow: hidden;
  background-color: silver;
}

.absolute {
  position: absolute;
  top: 0;
  left: 0;
  width: 50px;
  height: 50px;
  background-color: darkblue;
}

.wrapper {
  position: relative;
  overflow:hidden;
  width: 50%;
  height: 200px;
  overflow: hidden;
  background-color: yellow;
}

.wrapper > .absolute {
  background-color: darkcyan;
}
<div class="absolute"></div>
<h1>Some title</h1>

<div class="wrapper">
  <div class="absolute"></div>
  <h1>Some title</h1>
</div>

好的,我会尽量更清楚。如果你点击下面的链接,你可以看到我的JSFiddle。 background-color: silver标记中有body个。当我查看代码检查器时,我发现由于h1边距,body标签开始略低。但是background-color从顶部开始。这意味着代码检查员在骗我,身体从顶部开始。但是,为什么一个绝对定位的元素是body的直接元素不能从顶部开始呢?

JSFiddle

5 个答案:

答案 0 :(得分:13)

如上所述,顶级绝对定位元素的包含块为size_t operator(KeyType) const;,因为body相对定位。当body collapses的边距与h1的边距相比时,这会导致边距影响body,进而影响它所包含的绝对定位元素。相反,如果body 不是相对定位,则绝对定位的元素将锚定到初始包含块,并粘贴到视口的顶部,不受{{{}上任何有效边距的影响。 1}}(因为body不再是其包含的块)。

至于为什么银色背景会超出body元素,那就是by design

  

<强> 3.11.1。画布背景和根元素

     

根元素的背景成为画布的背景,其背景绘画区域扩展到覆盖整个画布。但是,任何图像的大小和位置都相对于根元素,就像它们仅为该元素绘制一样。 (换句话说,根据根元素确定背景定位区域。)根元素不再绘制该背景,即其背景的使用值是透明的。

     

<强> 3.11.2。画布背景和HTML&lt; body&gt;元件

     

对于其根元素是HTML body元素或XHTML body元素的文档:如果根元素上的'background-image'的计算值为'none'且其'background- color'是'透明',用户代理必须从该元素的第一个HTML HTML或XHTML html子元素传播背景属性的计算值。该BODY元素的背景属性的使用值是它们的初始值,并且传播的值被视为在根元素上指定它们。建议HTML文档的作者指定BODY元素的画布背景而不是body元素。

根元素的默认背景颜色始终为BODY,因此在HTML元素上设置背景颜色可防止银色背景从transparent元素中流失(并且您将会看到检查员实际上不是在骗你):

html
body

答案 1 :(得分:7)

这是因为collapsing margins。如何禁用它,您可以阅读一些文章/答案,例如this 您正在overflow: hidden使用.wrapper,并禁用此块的边距折叠。来自the specification

  

“溢出”而不是“可见”的方框的边距不会因其子边距而崩溃。

但似乎overflow: hidden<body>不起作用,因为如果我设置了 height: 0 / max-height: 0它也不起作用:

body {
    height: 0;
    max-height: 0;
}
<div>Some test text</div>

我认为这是因为(来自the specification):

  

UA必须将根元素上设置的'overflow'属性应用于视口。当根元素是HTML“HTML”元素或XHTML“html”元素,并且该元素具有HTML“BODY”元素或XHTML“body”元素作为子元素时,用户代理必须改为应用“溢出”属性从第一个这样的子元素到视口,如果根元素上的值是“可见的”。

这就是为什么<body>和第一<h1>之间的边距会崩溃(来自MDN):

  

父母和第一个/最后一个孩子
  如果没有边框,填充,内联内容或间隙将块的margin-top与其第一个子块的margin-top分开,或者没有边框,填充,内联内容,高度 min-height max-height 将块的margin-bottom与{{1}分开它的最后一个孩子,然后这些边缘崩溃。折叠的保证金最终在父母之外。

这就是为什么margin-bottom<html>之间的边距不会崩溃(来自the specification):

  

根元素框的边距不会崩溃。

我还注意到,如果<body>默认<html>background-color指定了<body> + background-color,则背景颜色会填充整个margin空间1}},例如:

<html>

但是,如果您将html, body { height: 100%; } body { margin: 20px; background-color: yellow; }设置为background-color,则其效果类似于普通块,例如:

<html>

总结一下,我建议你使用other approaches to disable collapsing margins,或为html, body { height: 100%; } html { background-color: red; } body { margin: 20px; background-color: yellow; }添加另一个包装器,例如:

<body>
body {
    margin: 0;
    padding: 0;
}

.body-wrapper {
    position: relative;
    overflow: hidden;
    background-color: silver;
}

.absolute {
    position: absolute;
    top: 0;
    left: 0;
    width: 50px;
    height: 50px;
    background-color: darkblue;
}

.wrapper {
    position: relative;
    width: 50%;
    height: 200px;
    overflow: hidden;
    background-color: yellow;
}

.wrapper > .absolute {
    background-color: darkcyan;
}

答案 2 :(得分:6)

这是另一种被称为margin-collapsing的现象。

我会试着解释发生了什么:

当您将div.absolute移动到绝对位置时,它会将其从内容流中拉出来。这会导致第一个h1充当其父级的第一个子级,在这种情况下为body

由于边缘折叠,h1的边距会在身体外部折叠。这就是为什么top: 0;不在视口的左上角。它位于body的左上角。

如果您需要这项工作,请添加html {position: relative; overflow: hidden:}

答案 3 :(得分:3)

这是一个有趣的行为,几乎没有在线找到的文档(至少在基本搜索中)。

我首先要说的是,我不知道绝对定位的盒子没有与body的角对齐的原因,正如预期的那样。但是这里有一些观察:

  1. 预期定位适用于IE11。 Chrome和FF存在差距。

  2. 如果您从position: relative移除body,预期定位将起作用(在Chrome,FF和IE11中进行测试)。 demo

  3. 如果您只将1px padding应用于body,它也适用于跨浏览器。 demo

  4. 如果您向body添加边框,它也可以使用。 demo

  5. <强>更新

    作为@BoltClock's accepted answer的快速附录,只需在原始代码中为根元素添加背景颜色即可轻松说明和理解此问题......

    html { background-color: red; }
    

    demo

    ...并删除h1上的默认保证金:

    h1 { margin: 0; }
    

    demo

答案 4 :(得分:1)

这是由h1具有默认边距引起的,这使bodyh1及其兄弟.absolute保持距离。

所以你要做的就是重置h1中的边距,就像你对body所做的那样:

每个保证金重置的

片段

&#13;
&#13;
body {
  position: relative;
  margin: 0;
  padding: 0;
  overflow: hidden;
  background-color: silver;
}
h1 {
  margin: 0;
 /*if you want to see full text, put this into the flow*/   
  position:relative;
  z-index:1;
}
.absolute {
  position: absolute;
  top: 0;
  left: 0;
  width: 50px;
  height: 50px;
  background-color: darkblue;
}
.wrapper {
  position: relative;
  overflow: hidden;
  width: 50%;
  height: 200px;
  overflow: hidden;
  background-color: yellow;
}
.wrapper > .absolute {
  background-color: darkcyan;
}
&#13;
<div class="absolute"></div>
<h1>Some title</h1>

<div class="wrapper">
  <div class="absolute"></div>
  <h1>Some title</h1>
</div>
&#13;
&#13;
&#13;

每个没有保证金重置的

片段

&#13;
&#13;
body {
  position: relative;
  /* margin: 0; */
  padding: 0;
  overflow: hidden;
  background-color: silver;
}
h1 {
  /* margin: 0; */
  /*if you want to see full text, put this into the flow*/
  position: relative;
  z-index: 1;
}
.absolute {
  position: absolute;
  top: 0;
  left: 0;
  width: 50px;
  height: 50px;
  background-color: darkblue;
}
.wrapper {
  position: relative;
  overflow: hidden;
  width: 50%;
  height: 200px;
  overflow: hidden;
  background-color: yellow;
}
.wrapper > .absolute {
  background-color: darkcyan;
}
&#13;
<div class="absolute"></div>
<h1>Some title</h1>

<div class="wrapper">
  <div class="absolute"></div>
  <h1>Some title</h1>
</div>
&#13;
&#13;
&#13;