Beyond awesome | 越而胜己

盒模型是 CSS 中连我都有点了解的基础。在矩形元素内容的外围有三层东西:外边距 margin、边框 border、内边距 padding

今天的内容来自书中第一部分《基础回顾》的第三章《盒模型》,我们将深入了解盒模型的应用,实现一个两列布局的网页。

宽度问题

假设我们想做一个两列布局的网页,左边是 70% 宽的主栏 main,右边是 30% 宽的侧边栏。我们可以写出如下的 CSS:

body {
  background-color: #eee;
  font-family: Helvetica, Arial, sans-serif;
}

header {
  color: #fff;
  background-color: #0072b0;
  border-radius: .5em;
}

main {
  display: block;  // ie bug fix
}

.main {
  float: left;
  width: 70%;
  background-color: #fff;
  border-radius: .5em;
}

.sidebar {
  float: left;
  width: 30%;
  padding: 1.5em;
  background-color: #fff;
  border-radius: .5em;
}

但是这段 CSS 使得侧边栏跑到了第二行去,因为一个 70% 宽的元素和一个 30% 宽的元素加起来宽度却超过了 100%。

出现这样的错误的原因是 .sidebar 的内边距加大了它的宽度,使得总宽度超出了 3em

如何解决这样的问题?一种方法是减少 .sidebar 的宽度,比如改成 26%。但这种方式显然不解决问题,在某些情况下仍然可能翻车。另一种方式是用 calc 计算宽度,比如 calc(30% - 3em),但也并不优雅。

最好的解决方式是调整盒模型。在默认的盒模型 content-box 中,元素的高和宽指的是 margin 内圈的高和宽。因此,paddingborder 的宽度都将额外增加元素的尺寸。我们可以将 box-sizing 属性设为 border-box,此时元素的高和宽指的是 border 外圈的高和宽,就避免了计算 borderpadding 占用屏幕的空间。

给  .main.sidebar 都加上 box-sizing: border-box; 之后,问题得到了解决:

由于 border-boxcontent-box 有用的多,我们可以将默认值设为 border-box

*,
::before,
::after {
  box-sizing: border-box;
}

这种方式将把所有元素都改为 border-box。但是当我们使用一些使用 content-box 的第三方组建的时候,就无法将它们的 box-sizing 改回 content-box。一种解决方案是采用如下的代码:

:root {
  box-sizing: border-box;
}

*,
::before,
::after {
  box-sizing: inherit;
}

.third-party-component {
  box-sizing: content-box;
}

由于层叠可以覆盖继承,这样就可以保留某些元素的 content-box 了。

此时 .main.sidebar 还是紧贴在一起,我们可以用 margin-left: 1.5em; 将它们分开。但是由于 margin 是在宽度之外的,所以我们不得不用 calc() 来重新计算 .sidebar 的宽度:width: calc(30% - 1.5em);

这样我们就得到了想要的两列布局:

未完待续

下一篇笔记将会讨论盒模型中的高度问题。

You’ve successfully subscribed to Skyward
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Your link has expired
Success! Check your email for magic link to sign-in.