为什么 top: 0 不能处理相对于 body 的绝对定位元素?
Why doesn't top: 0 work on absolutely-positioned elements relative to body?
您可以在下面的代码中看到,h1
将主体向下推,而绝对定位块 .absolute
不会粘在顶部。但您也可以看到,同一个块粘在其父块 .wrapper
的顶部。为什么?
我不是在问怎么做这个把戏;我知道如何,例如padding 而不是 margin 到 h1,或者 clearfix 到 parent 等等。
我只对一件事感兴趣:为什么 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>
好的,我会尽量说得更清楚。如果你点击下面的link,你可以看到我的JSFiddle。 body
标签中有background-color: silver
。当我查看代码检查器时,我发现由于 h1 边距,正文标签开始略低。但是 background-color
从顶部开始。这意味着代码检查员在骗我,body 从顶部开始。但是,为什么作为 body
的直接子元素的绝对定位元素不从顶部开始呢?
这是一个有趣的行为,在网上几乎找不到文档(至少在基本搜索中是这样)。
首先我要说我不知道为什么绝对定位的框没有像预期的那样与 body
的角对齐。但这里有一些观察结果:
预期的定位适用于 IE11。差距存在于Chrome和FF.
如果从 body
中删除 position: relative
,则预期的定位有效(在 Chrome、FF 和 IE11 中测试)。 demo
如果你只应用 1px padding
到 body
,它也可以跨浏览器工作。 demo
如果给body
加上边框也可以。 demo
更新
作为 的快速补充,只需在原始代码中向根元素添加背景色即可轻松说明和理解此问题...
html { background-color: red; }
... 并通过删除 h1
:
上的默认边距
h1 { margin: 0; }
这是由于 h1
有一个默认边距,这使得 body
与 h1
及其同级 .absolute
分开。
所以您所要做的就是重置 h1
中的边距,就像您对 body
:
所做的那样
每个边距都已重置的片段
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;
}
<div class="absolute"></div>
<h1>Some title</h1>
<div class="wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
</div>
每个无边距重置的片段
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;
}
<div class="absolute"></div>
<h1>Some title</h1>
<div class="wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
</div>
这是被称为 margin-collapsing
的现象的另一个实例。
我会尝试解释发生了什么:
当您使用绝对位置移动 div.absolute
时,它会将其从内容流中拉出。这会导致第一个 h1
作为其父项的第一个子项,在本例中为 body
。
h1
的边距然后由于边距折叠而在 外部 折叠。这就是 top: 0;
不在视口左上角的原因。它位于 body
.
的左上角
如果您需要让它工作,请添加一个 html {position: relative; overflow: hidden:}
。
因为collapsing margins. How to disable it, you could read in some articles/answers, for example, this.
您正在为 .wrapper
使用 overflow: hidden
,它会禁用此块的折叠边距。来自 the specification:
Margins of a box with ‘overflow’ other than ‘visible’ do not collapse with its children's margins.
但似乎 overflow: hidden
对 <body>
不起作用,因为如果我设置
height: 0
/max-height: 0
也不行:
body {
height: 0;
max-height: 0;
}
<div>Some test text</div>
我认为是因为(来自the specification):
UAs must apply the 'overflow' property set on the root element to the viewport. When the root element is an HTML "HTML" element or an XHTML "html" element, and that element has an HTML "BODY" element or an XHTML "body" element as a child, user agents must instead apply the 'overflow' property from the first such child element to the viewport, if the value on the root element is 'visible'.
这就是为什么 <body>
和第一个 <h1>
之间的边距崩溃(来自 MDN):
Parent and first/last child
If there is no border, padding, inline content, or clearance to separate the margin-top
of a block with the margin-top
of its first child block, or no border, padding, inline content, height, min-height, or max-height to separate the margin-bottom
of a block with the margin-bottom
of its last child, then those margins collapse. The collapsed margin ends up outside the parent.
这就是为什么 <html>
和 <body>
之间的边距不会折叠(来自 the specification):
Margins of the root element's box do not collapse.
我也注意到如果<html>
有默认的background-color
并且<body>
指定了background-color
+margin
,背景颜色会填充整个[= <html>
的 91=],例如:
html, body {
height: 100%;
}
body {
margin: 20px;
background-color: yellow;
}
但是如果你将background-color
设置为<html>
,它就像一个普通的块一样工作,例如:
html, body {
height: 100%;
}
html {
background-color: red;
}
body {
margin: 20px;
background-color: yellow;
}
我总结一下,我建议你使用other approaches to disable collapsing margins,或者为<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;
}
<div class="body-wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
<div class="wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
</div>
</div>
如前所述,顶级绝对定位元素的包含块是body
,因为body
是相对定位的。当 h1
collapses 的边距与 body
的边距相同时,这会导致边距影响 body
,进而影响它包含的绝对定位元素。相反,如果 body
不是 相对定位,绝对定位的元素将锚定到初始包含块,并粘在视口的顶部,不受任何有效边距的影响在 body
上(因为 body
不再是它的包含块)。
至于为什么银色背景会超出 body
元素,那就是 by design:
3.11.1. The Canvas Background and the Root Element
The background of the root element becomes the background of the canvas and its background painting area extends to cover the entire canvas. However, any images are sized and positioned relative to the root element as if they were painted for that element alone. (In other words, the background positioning area is determined as for the root element.) The root element does not paint this background again, i.e., the used value of its background is transparent.
3.11.2. The Canvas Background and the HTML <body> Element
For documents whose root element is an HTML HTML
element or an XHTML html
element: if the computed value of ‘background-image’ on the root element is ‘none’ and its ‘background-color’ is ‘transparent’, user agents must instead propagate the computed values of the background properties from that element's first HTML BODY
or XHTML body
child element. The used values of that BODY element's background properties are their initial values, and the propagated values are treated as if they were specified on the root element. It is recommended that authors of HTML documents specify the canvas background for the BODY
element rather than the HTML
element.
根元素的默认背景色始终为 transparent
,因此在 html
元素上设置背景色可防止银色背景渗出 body
元素(并且您会看到检查员其实没有骗你):
html {
background-color: white;
}
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>
您可以在下面的代码中看到,h1
将主体向下推,而绝对定位块 .absolute
不会粘在顶部。但您也可以看到,同一个块粘在其父块 .wrapper
的顶部。为什么?
我不是在问怎么做这个把戏;我知道如何,例如padding 而不是 margin 到 h1,或者 clearfix 到 parent 等等。
我只对一件事感兴趣:为什么 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>
好的,我会尽量说得更清楚。如果你点击下面的link,你可以看到我的JSFiddle。 body
标签中有background-color: silver
。当我查看代码检查器时,我发现由于 h1 边距,正文标签开始略低。但是 background-color
从顶部开始。这意味着代码检查员在骗我,body 从顶部开始。但是,为什么作为 body
的直接子元素的绝对定位元素不从顶部开始呢?
这是一个有趣的行为,在网上几乎找不到文档(至少在基本搜索中是这样)。
首先我要说我不知道为什么绝对定位的框没有像预期的那样与 body
的角对齐。但这里有一些观察结果:
预期的定位适用于 IE11。差距存在于Chrome和FF.
如果从
body
中删除position: relative
,则预期的定位有效(在 Chrome、FF 和 IE11 中测试)。 demo如果你只应用 1px
padding
到body
,它也可以跨浏览器工作。 demo如果给
body
加上边框也可以。 demo
更新
作为
html { background-color: red; }
... 并通过删除 h1
:
h1 { margin: 0; }
这是由于 h1
有一个默认边距,这使得 body
与 h1
及其同级 .absolute
分开。
所以您所要做的就是重置 h1
中的边距,就像您对 body
:
每个边距都已重置的片段
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;
}
<div class="absolute"></div>
<h1>Some title</h1>
<div class="wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
</div>
每个无边距重置的片段
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;
}
<div class="absolute"></div>
<h1>Some title</h1>
<div class="wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
</div>
这是被称为 margin-collapsing
的现象的另一个实例。
我会尝试解释发生了什么:
当您使用绝对位置移动 div.absolute
时,它会将其从内容流中拉出。这会导致第一个 h1
作为其父项的第一个子项,在本例中为 body
。
h1
的边距然后由于边距折叠而在 外部 折叠。这就是 top: 0;
不在视口左上角的原因。它位于 body
.
如果您需要让它工作,请添加一个 html {position: relative; overflow: hidden:}
。
因为collapsing margins. How to disable it, you could read in some articles/answers, for example, this.
您正在为 .wrapper
使用 overflow: hidden
,它会禁用此块的折叠边距。来自 the specification:
Margins of a box with ‘overflow’ other than ‘visible’ do not collapse with its children's margins.
但似乎 overflow: hidden
对 <body>
不起作用,因为如果我设置
height: 0
/max-height: 0
也不行:
body {
height: 0;
max-height: 0;
}
<div>Some test text</div>
我认为是因为(来自the specification):
UAs must apply the 'overflow' property set on the root element to the viewport. When the root element is an HTML "HTML" element or an XHTML "html" element, and that element has an HTML "BODY" element or an XHTML "body" element as a child, user agents must instead apply the 'overflow' property from the first such child element to the viewport, if the value on the root element is 'visible'.
这就是为什么 <body>
和第一个 <h1>
之间的边距崩溃(来自 MDN):
Parent and first/last child
If there is no border, padding, inline content, or clearance to separate themargin-top
of a block with themargin-top
of its first child block, or no border, padding, inline content, height, min-height, or max-height to separate themargin-bottom
of a block with themargin-bottom
of its last child, then those margins collapse. The collapsed margin ends up outside the parent.
这就是为什么 <html>
和 <body>
之间的边距不会折叠(来自 the specification):
Margins of the root element's box do not collapse.
我也注意到如果<html>
有默认的background-color
并且<body>
指定了background-color
+margin
,背景颜色会填充整个[= <html>
的 91=],例如:
html, body {
height: 100%;
}
body {
margin: 20px;
background-color: yellow;
}
但是如果你将background-color
设置为<html>
,它就像一个普通的块一样工作,例如:
html, body {
height: 100%;
}
html {
background-color: red;
}
body {
margin: 20px;
background-color: yellow;
}
我总结一下,我建议你使用other approaches to disable collapsing margins,或者为<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;
}
<div class="body-wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
<div class="wrapper">
<div class="absolute"></div>
<h1>Some title</h1>
</div>
</div>
如前所述,顶级绝对定位元素的包含块是body
,因为body
是相对定位的。当 h1
collapses 的边距与 body
的边距相同时,这会导致边距影响 body
,进而影响它包含的绝对定位元素。相反,如果 body
不是 相对定位,绝对定位的元素将锚定到初始包含块,并粘在视口的顶部,不受任何有效边距的影响在 body
上(因为 body
不再是它的包含块)。
至于为什么银色背景会超出 body
元素,那就是 by design:
3.11.1. The Canvas Background and the Root Element
The background of the root element becomes the background of the canvas and its background painting area extends to cover the entire canvas. However, any images are sized and positioned relative to the root element as if they were painted for that element alone. (In other words, the background positioning area is determined as for the root element.) The root element does not paint this background again, i.e., the used value of its background is transparent.
3.11.2. The Canvas Background and the HTML <body> Element
For documents whose root element is an HTML
HTML
element or an XHTMLhtml
element: if the computed value of ‘background-image’ on the root element is ‘none’ and its ‘background-color’ is ‘transparent’, user agents must instead propagate the computed values of the background properties from that element's first HTMLBODY
or XHTMLbody
child element. The used values of that BODY element's background properties are their initial values, and the propagated values are treated as if they were specified on the root element. It is recommended that authors of HTML documents specify the canvas background for theBODY
element rather than theHTML
element.
根元素的默认背景色始终为 transparent
,因此在 html
元素上设置背景色可防止银色背景渗出 body
元素(并且您会看到检查员其实没有骗你):
html {
background-color: white;
}
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>