间距

CSS 播客 - 013: 间距

假设您有一组三个盒子,彼此堆叠在一起,并且您希望它们之间有间距。您能想到多少种在 CSS 中实现这一目标的方法?

Three stacked boxes with a downward arrow

margin 属性可能会为您提供所需的效果,但它也可能会添加您不希望的额外间距。例如,您如何仅定位这些元素之间的间距?在这种情况下,类似 gap 的属性可能更合适。在 UI 中调整间距的方法有很多种,每种方法都有其自身的优点和缺点。

HTML 间距

HTML 本身提供了一些用于分隔元素的方法。<br><hr> 元素允许您在块方向上分隔元素,如果您使用的是基于拉丁语的语言,则为从上到下。

如果您使用 <br> 元素,它将创建一个换行符,就像您在文字处理器中按下 Enter 键一样。

<hr> 创建一条水平线,两侧都有空间,称为 margin

除了使用 HTML 元素外,HTML 实体也可以创建空格。HTML 实体是浏览器替换为字符实体的保留字符串。例如,如果您在 HTML 文件中键入 &copy;,它将被转换为 © 字符。&nbsp; 实体被转换为不间断空格字符,从而提供内联空格。但请注意,因为此字符的不间断方面会将两个元素缝合在一起,这可能会导致奇怪的行为。

Margin

如果您想在元素外部添加空格,请使用 margin 属性。Margin 就像在元素周围添加一个缓冲垫。margin 属性是 margin-topmargin-rightmargin-bottommargin-left 的简写。

A diagram of the four main areas of the box model.

margin 简写以特定顺序应用属性:上、右、下和左。您可以使用“TRouBLe”来记住这些顺序。

The word 'Trouble' running downwards with T, R, B and L
extending to Top, Right, Bottom and Left.
A box with arrows showing the directions too.

margin 简写也可以与一个、两个或三个值一起使用。添加第四个值可以让您设置每个单独的边。这些值的应用方式如下:

  • 一个值将应用于所有边。(margin: 20px)。
  • 两个值:第一个值将应用于顶部和底部边,第二个值将应用于左侧和右侧边。(margin: 20px 40px
  • 三个值:第一个值是 top,第二个值是 left right,第三个值是 bottom。(margin: 20px 40px 30px)。

Margin 可以使用长度、百分比或 auto 值定义,例如 1em20%。如果您使用百分比,该值将根据元素包含块的宽度计算。

这意味着如果您的元素包含块的宽度为 250px,并且您的元素具有 margin 值为 20%:则您元素的每一侧的计算 margin 将为 50px

您也可以对 margin 使用 auto 值。对于具有受限大小的块级元素,auto margin 将占用其应用方向上的可用空间。一个很好的例子是 flexbox 模块中的这个例子,其中项目互相推开。

auto margin 的另一个很好的例子是水平居中的包装器,它具有最大宽度。这种包装器通常用于在网站上创建一致的中心列。

.wrapper {
    max-width: 400px;
    margin: 0 auto;
}

在这里,margin 从顶部和底部(块)侧移除,而 auto 分享左侧和右侧(内联)侧之间的空间。

负 margin

负值也可以用于 margin。它不是在相邻的同级元素之间添加空格,而是会减少它们之间的空格。如果声明的负值大于可用空间,则可能导致元素重叠。

Margin 折叠

Margin 折叠是一个棘手的概念,但在构建界面时您会经常遇到它。假设您有两个元素:一个标题和一个段落,它们都具有垂直 margin。

<article>
  <h1>My heading with teal margin</h1>
  <p>A paragraph of text that has blue margin on it, following the heading with margin.</p>
</article>
h1 {
    margin-bottom: 2rem;
}

p {
    margin-top: 3rem;
}

乍一看,您可能会认为段落与标题之间将有 5em 的间距,因为 2rem3rem 加起来计算为 5rem。但是,由于垂直 margin 折叠,因此实际空间为 3rem

Margin 折叠的工作原理是选择两个相邻元素中,在相邻侧设置的垂直 margin 的最大值。h1 的底部与 p 的顶部相遇,因此选择 h1 的底部 margin 和 p 的顶部 margin 的最大值。如果 h1 具有 3.5rem 的底部 margin,则它们之间的空间将为 3.5rem,因为它大于 3rem。只有块 margin 会折叠,内联(水平)margin 不会折叠。

Margin 折叠也有助于处理空元素。如果您有一个段落,其顶部和底部 margin 为 20px,它只会创建 20px 的空间:而不是 40px。但是,如果在此元素内部添加任何内容,包括 padding,则其 margin 将不再自身折叠,并将被视为任何具有内容的框。

检查您的理解情况

测试您对 margin 折叠的知识

如果两个堆叠在一起的元素都具有 20px 的顶部 margin 和 30px 的底部 margin,那么它们之间将有多少空间?

10px
再试一次!
20px
不太对
30px
CSS 将采用元素之间 margin 空间中较大的那个,没错!
40px
再试一次!

阻止 margin 折叠

如果您将元素设置为绝对定位,使用 position: absolute,则 margin 将不再折叠。如果您也使用 float 属性,margin 也不会折叠。

如果您在两个具有块 margin 的元素之间有一个没有 margin 的元素,则 margin 也不会折叠,因为两个具有块 margin 的元素不再是相邻的同级元素:它们只是同级元素。

布局课程中,您学习了 flexbox 和 grid 容器与块容器非常相似,但处理其子元素的方式却大相径庭。margin 折叠也是如此。

如果我们采用课程中的原始示例并应用列方向的 flexbox,则 margin 会组合而不是折叠。这可以为布局工作提供可预测性,而这正是 flexbox 和 grid 容器的设计目的。

Margin 和 margin 折叠可能很难理解,但详细了解它们的工作原理非常有用,因此强烈建议阅读这份详细的解释

Padding

margin 在框外部创建空间不同,padding 属性在框的内部创建空间:就像隔热层一样。

A box with arrows pointing inwards to show that padding lives inside a box

根据您使用的盒模型(在盒模型课程中介绍过),padding 也会影响元素的整体尺寸。

padding 属性是 padding-toppadding-rightpadding-bottompadding-left 的简写。与 margin 一样,padding 也具有逻辑属性:padding-block-startpadding-inline-endpadding-block-endpadding-inline-start

定位

布局模块中也介绍过,如果您为 position 设置的值不是 static,则可以使用 toprightbottomleft 属性来分隔元素。这些方向值在行为方式上存在一些差异:

  • 即使您设置这些值,具有 position: relative 的元素也会保持其在文档流中的位置。它们也将相对于您元素的位置。
  • 具有 position: absolute 的元素将根据相对父元素的位置确定方向值。
  • 具有 position: fixed 的元素将根据视口确定方向值。
  • 具有 position: sticky 的元素仅在其停靠/粘滞状态下应用方向值。

逻辑属性模块中,您学习了 inset-blockinset-inline 属性,它们允许您设置遵循书写模式的方向值。

这两个属性都是组合 startend 值的简写,因此接受一个值来设置为 startend,或者接受两个单独的值。

Grid 和 flexbox

最后,在 grid 和 flexbox 中,您都可以使用 gap 属性在子元素之间创建空间。gap 属性是 row-gapcolumn-gap 的简写,它接受一个或两个值,可以是长度或百分比。您也可以使用关键字,例如 unsetinitialinherit。如果您仅定义一个值,则相同的 gap 将应用于行和列,但是如果您定义了两个值,则第一个值是 row-gap,第二个值是 column-gap

对于 flexbox 和 grid,您还可以使用其分布和对齐功能来创建空间,我们在grid 模块flexbox 模块中对此进行了介绍。

A diagram representation of a grid with gaps

创建一致的间距

选择一种策略并坚持使用它,以帮助您创建具有良好流动性和节奏的一致用户界面,这是一个非常好的主意。实现此目的的一个好方法是为您的间距使用一致的度量标准。

例如,您可以承诺使用 20px 作为元素之间所有间隙(称为 gutters)的一致度量标准,以便所有布局看起来和感觉一致。您也可以决定使用 1em 作为流内容之间的垂直间距,这将基于元素的 font-size 实现一致的间距。无论您选择什么,都应将这些值另存为变量(或 CSS 自定义属性)以标记这些值,并使一致性更容易实现。

Consistent spacing between elements,
using either 20px for a layout or 1em for flow content.

:root {
  --gutter: 20px;
  --spacing: 1em;
}

h1 {
  margin-left: var(--gutter);
  margin-top: var(--spacing);
}

像这样使用自定义属性允许您定义一次,然后在整个 CSS 中使用它们。当它们更新时(在元素本地或全局范围内),这些值将通过层叠传递下去,并且更新后的值将得到反映。

检查您的理解情况

测试您对间距的知识

在以下情况下,可以安全地使用 HTML 进行间距...

它只有一个。
再试一次!
没有人会注意到。
再试一次!
它只是为了空格。
再试一次!
它有助于理解文档。
答对了!

要在框内部创建空间,请使用...

Margin
Margin 用于将内容推到框外部。
HTML
这些用于分隔内容。
Gap
Gap 用于分隔框之间的空间。
Padding
Padding 用于在框内部创建空间。

要在框外部创建空间,请使用...

Margin
Margin 用于将内容推到框外部。
HTML
这些用于分隔内容。
Gap
Gap 用于分隔框之间的空间。
Padding
Padding 用于在框内部创建空间。

要在框之间创建空间,请使用...

Margin
Margin 用于将内容推到框外部。
HTML
这些用于分隔内容。
Gap
Gap 用于分隔框之间的空间。
Padding
Padding 用于在框内部创建空间。