<html> , <body> , padding, margin, 100vh and calc()

5

考虑下面的代码片段:

html {
  margin: 0;
  padding: 0;
  background-color: blue;
}

body {
  margin: 0;
  padding: 0;
  background-color: green;
  min-height: 100vh;
}
<section style="min-height: 50px; background-color: pink;"></section>

正如预期的那样,body元素以绿色填充整个视口,在其上方有一个粉色的section元素。
现在,假设您想要做一些非常简单的事情,比如在section元素中设置一个margin: style="min-height: 50px; background-color: pink; margin-bottom: 10px;"。出乎意料的是,html元素的蓝色条出现在视口底部。

html {
  margin: 0;
  padding: 0;
  background-color: blue;
}

body {
  margin: 0;
  padding: 0;
  background-color: green;
  min-height: 100vh;
}
<section style="min-height: 50px; background-color: pink; margin-bottom: 10px;"></section>

问题1) 为什么会出现这种行为?我无法理解。

纠正这种行为的一种方法是在元素中包含填充和min-height calc() 调整:

html {
  margin: 0;
  padding: 0;
  background-color: blue;
}

body {
  margin: 0;
  padding: 0;
  padding-bottom: 1px;
  background-color: green;
  min-height: calc(100vh - 1px);
}
<section style="min-height: 50px; background-color: pink; margin-bottom: 10px;"></section>

然而,这个解决方案需要使用一个我不太熟悉的技巧。

问题2 是否有更好的解决方案?(即:更直观、更易读)


是我眼花了,还是这三个代码片段底部都有一条蓝色的条纹?它们在我看来完全一样。 - Svenmarim
2个回答

2
您面临的是一个边距折叠问题。您为部分应用的底部边距与body的底部边距折叠,因此它被应用到了body而不是该部分。
正如您可以在这里阅读到的:

块级元素的上下边距有时会合并(折叠)成为单个边距,其大小为各个边距中最大的那个(或者如果它们相等,则只有其中一个),这种行为称为边距折叠

边距折叠发生在三种基本情况下:

相邻兄弟

父元素和第一个/最后一个子元素

空块级元素

因此,在您的情况下,您有10像素的底部边距,它会将滚动条添加到您的页面,因为body具有min-height:100vh

html {
  margin: 0;
  padding: 0;
  background-color: blue;
}

body {
  margin: 0;
  padding: 0;
  background-color: green;
  min-height: 100vh;
}
<section style="min-height: 50px; background-color: pink;margin-bottom: 10px;"></section>

为避免这种行为,您只需要避免产生边距折叠。因此,您可以像您所做的那样添加一个小的填充或者边框,然后不要忘记还要加上 box-sizing:border-box 以避免改变高度并使用 calc

html {
  margin: 0;
  padding: 0;
  background-color: blue;
}

body {
  margin: 0;
  padding: 0;
  background-color: green;
  min-height: 100vh;
  border-bottom:1px solid transparent;
  /* OR padding-bottom:1px */
  box-sizing:border-box;
}
<section style="min-height: 50px; background-color: pink;margin-bottom: 10px;"></section>

您也可以使用flex,因为在flex中没有边距折叠(请查看下面的链接获取更多方法):

html {
  margin: 0;
  padding: 0;
  background-color: blue;
}

body {
  margin: 0;
  padding: 0;
  background-color: green;
  min-height: 100vh;
  display:flex;
  flex-direction:column;
}
<section style="min-height: 50px; background-color: pink;margin-bottom: 10px;"></section>


一些可能会帮助你获取更多信息的链接:

https://css-tricks.com/what-you-should-know-about-collapsing-margins/

如何取消折叠边距?

CSS 边距恐惧症;边距会在父元素外添加空间

子元素的边距会移动父元素

flexbox 中的边距折叠


请查看 https://jsbin.com/qekonaruka/1/edit?html,output。如果底部边距折叠,为什么浮动的黄色框被推下了 section 元素底部边距的大小? - Alohci
1
box-sizing: border-box; 这对于此问题和其他几个问题非常有帮助。 - Mark Messa
1
仅供记录,还有另一种有趣的方法可以禁用边距折叠,而且需要更少的编码:padding: 0.1px - Mark Messa
1
然而,出于可读性的考虑,禁用外边距折叠的最佳方法似乎是使用 flexbox。 - Mark Messa
@Alohci:折叠穿过定义在§9.5.1中被引用:“4.浮动框的外部顶部不能高于其包含块的顶部。当浮动出现在两个折叠边距之间时,浮动位置就像它有一个参与流程的空匿名块父级一样定位。这样的父级的位置由边距折叠部分的规则定义。”然而,重要的部分在其他地方 - BoltClock
显示剩余5条评论

-3

我也不知道为什么会出现这种情况,但你可以尝试使用以下CSS来克服这种情况:

body {margin: 0; padding: 0; background-color: green; position:absolute; left:0; top:0; right:0; bottom:0; overflow:auto;}

这段代码的问题在于你会失去一些灵活性(尽管我在原始问题中没有提到这个限制)。例如:如果section元素的高度增加,body元素将不会随之增加,而且背景在100vh后会变成蓝色。 - Mark Messa
@MarkMessa 实际上,当内容增加时,页面会相应地出现滚动条。或者您可以尝试使用以下代码:html {margin: 0; padding: 0; background-color: blue; height:100vh;} body {margin: 0; padding: 0; background-color: green; min-height: 100%;} - Hanif
实际上,当内容增加时,页面会相应地出现滚动条。奇怪的是,在我的浏览器中,body元素保持固定的100vh,而html随着部分内容的增加而增加(蓝色背景)。 - Mark Messa
或者您可以尝试使用HTML。html {height: 100vt} body {min-height: 100%}的问题在于它不能解决section {margin-top: 10px}产生的蓝色条纹问题,当内容增加时也不能解决section {min-height: 1500px}的问题。 - Mark Messa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接