间距

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,那么它们之间将有多少空间?

40px
20px
30px
10px

阻止 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 进行间距...

它只是为了空格。
它只有一个。
它有助于理解文档。
没有人会注意到。

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

Gap
HTML
Margin
Padding

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

HTML
Gap
Padding
Margin

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

HTML
Margin
Gap
Padding