浮动元素旁边的 margin-top 的意外结果
Unexpected result from margin-top next to a floated element
我遇到这样的布局问题:
.wrapper {
clear: both;
background-color: #ccc;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
.main
和 .side
元素需要对齐。正如您在上面的代码片段中看到的,一切都很好,除非 .top
元素没有高度,在这种情况下 margin-top
规则会导致它们倾斜。以下都是"fix"问题,但各有缺点:
- 向
.wrapper
添加边框(我可能可以接受透明边框,但我真的不喜欢这个,因为它感觉像是一个肮脏的黑客,我宁愿不添加边框。对于由于某种原因,边框需要至少有 1 像素的宽度,否则这不起作用)
.wrapper {
clear: both;
background-color: #ccc;
border: 1px solid #000;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
- 将
overflow: hidden
添加到 .wrapper
(这会隐藏部分元素并导致其他元素落在错误的位置)
- 将
overflow: auto
添加到 .wrapper
(这会在某些情况下添加滚动条)
最后两个在我的代码片段中并不明显,但在实际应用中它们会导致问题 here。
我强烈怀疑这个问题与 Why doesn't the height of a container element increase if it contains floated elements? and CSS container doesn't stretch to accommodate floats 有关,但我已经尝试了很多建议,none 似乎完全解决了这个问题 - 可能是因为我的一个 div 是浮动的另一个不是。
因为这是一个大型应用程序的一部分,我不想彻底改变布局,只需要一些 css 来保持 .main
和 .side
对齐,无论这些元素之前的内容。
您可以使用网格更优雅地完成此操作。这里是网格代码:
.wrapper {
display: grid;
grid-template-areas:
"top top"
"side main";
grid-template-columns: 100px 1fr;
}
.top{grid-area:top}
.side{grid-area:side}
.main{grid-area:main}
请注意我能够注释掉多少其他元素并仍然保持所需的布局。
.wrapper {
/*clear: both;*/
background-color: #ccc;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
/*margin-top: 20px;*/
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
/*width: 100px;
float: left;*/
background: lightblue;
}
.main {
/*margin-left: 100px;*/
background: lightgreen;
}
.wrapper {
display: grid;
grid-template-areas:
"top top"
"side main";
grid-template-columns: 100px 1fr;
}
.top{grid-area:top}
.side{grid-area:side}
.main{grid-area:main}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
你可以把主元素设为inline-block
,然后用calc来设置宽度。这应该不会对您的布局产生太大影响,您将获得正确的输出:
.main {
width:calc(100% - 100px);
display:inline-block;
background: lightgreen;
}
完整代码:
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
width:calc(100% - 100px);
display:inline-block;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
另一个 hacky 想法是确保您的顶部元素永远不会为空:
.top:empty {
font-size:0;
}
.top:empty::before {
content: ""; /* a random character */
}
完整代码
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
.top:empty {
font-size:0;
}
.top:empty::before {
content: ""; /* a random character */
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
您也可以考虑同样的技巧,但在主包装器上使用伪元素:
.wrapper::before {
content: ""; /* a random character */
display:block;
font-size:0;
}
完整代码
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
.wrapper::before {
content: ""; /* a random character */
display:block;
font-size:0;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
您还可以使包装器 inline-block
的宽度等于 100%,它的行为几乎与块元素相同:
.wrapper {
background-color: #ccc;
display:inline-block;
width:100%;
vertical-align:top; /* avoid some unwanted white space issue*/
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
关于解释,您正面临 the specification 中描述的页边距折叠问题:
Two margins are adjoining if and only if:
- both belong to in-flow block-level boxes that participate in the same block formatting context
- no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
- both belong to vertically-adjacent box edges, i.e. form one of:
- top margin of a box and top margin of its first in-flow child
我遇到这样的布局问题:
.wrapper {
clear: both;
background-color: #ccc;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
.main
和 .side
元素需要对齐。正如您在上面的代码片段中看到的,一切都很好,除非 .top
元素没有高度,在这种情况下 margin-top
规则会导致它们倾斜。以下都是"fix"问题,但各有缺点:
- 向
.wrapper
添加边框(我可能可以接受透明边框,但我真的不喜欢这个,因为它感觉像是一个肮脏的黑客,我宁愿不添加边框。对于由于某种原因,边框需要至少有 1 像素的宽度,否则这不起作用)
.wrapper {
clear: both;
background-color: #ccc;
border: 1px solid #000;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
- 将
overflow: hidden
添加到.wrapper
(这会隐藏部分元素并导致其他元素落在错误的位置) - 将
overflow: auto
添加到.wrapper
(这会在某些情况下添加滚动条)
最后两个在我的代码片段中并不明显,但在实际应用中它们会导致问题 here。
我强烈怀疑这个问题与 Why doesn't the height of a container element increase if it contains floated elements? and CSS container doesn't stretch to accommodate floats 有关,但我已经尝试了很多建议,none 似乎完全解决了这个问题 - 可能是因为我的一个 div 是浮动的另一个不是。
因为这是一个大型应用程序的一部分,我不想彻底改变布局,只需要一些 css 来保持 .main
和 .side
对齐,无论这些元素之前的内容。
您可以使用网格更优雅地完成此操作。这里是网格代码:
.wrapper {
display: grid;
grid-template-areas:
"top top"
"side main";
grid-template-columns: 100px 1fr;
}
.top{grid-area:top}
.side{grid-area:side}
.main{grid-area:main}
请注意我能够注释掉多少其他元素并仍然保持所需的布局。
.wrapper {
/*clear: both;*/
background-color: #ccc;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
/*margin-top: 20px;*/
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
/*width: 100px;
float: left;*/
background: lightblue;
}
.main {
/*margin-left: 100px;*/
background: lightgreen;
}
.wrapper {
display: grid;
grid-template-areas:
"top top"
"side main";
grid-template-columns: 100px 1fr;
}
.top{grid-area:top}
.side{grid-area:side}
.main{grid-area:main}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
你可以把主元素设为inline-block
,然后用calc来设置宽度。这应该不会对您的布局产生太大影响,您将获得正确的输出:
.main {
width:calc(100% - 100px);
display:inline-block;
background: lightgreen;
}
完整代码:
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
width:calc(100% - 100px);
display:inline-block;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
另一个 hacky 想法是确保您的顶部元素永远不会为空:
.top:empty {
font-size:0;
}
.top:empty::before {
content: ""; /* a random character */
}
完整代码
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
.top:empty {
font-size:0;
}
.top:empty::before {
content: ""; /* a random character */
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
您也可以考虑同样的技巧,但在主包装器上使用伪元素:
.wrapper::before {
content: ""; /* a random character */
display:block;
font-size:0;
}
完整代码
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
.wrapper::before {
content: ""; /* a random character */
display:block;
font-size:0;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
您还可以使包装器 inline-block
的宽度等于 100%,它的行为几乎与块元素相同:
.wrapper {
background-color: #ccc;
display:inline-block;
width:100%;
vertical-align:top; /* avoid some unwanted white space issue*/
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
关于解释,您正面临 the specification 中描述的页边距折叠问题:
Two margins are adjoining if and only if:
- both belong to in-flow block-level boxes that participate in the same block formatting context
- no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
- both belong to vertically-adjacent box edges, i.e. form one of:
- top margin of a box and top margin of its first in-flow child