CSS 播客 - 013: 间距
假设您有一组三个盒子,彼此堆叠在一起,并且您希望它们之间有间距。您能想到多少种在 CSS 中实现这一目标的方法?
margin
属性可能会为您提供所需的效果,但它也可能会添加您不希望的额外间距。例如,您如何仅定位这些元素之间的间距?在这种情况下,类似 gap
的属性可能更合适。在 UI 中调整间距的方法有很多种,每种方法都有其自身的优点和缺点。
HTML 间距
HTML 本身提供了一些用于分隔元素的方法。<br>
和 <hr>
元素允许您在块方向上分隔元素,如果您使用的是基于拉丁语的语言,则为从上到下。
如果您使用 <br>
元素,它将创建一个换行符,就像您在文字处理器中按下 Enter 键一样。
<hr>
创建一条水平线,两侧都有空间,称为 margin
。
除了使用 HTML 元素外,HTML 实体也可以创建空格。HTML 实体是浏览器替换为字符实体的保留字符串。例如,如果您在 HTML 文件中键入 ©
,它将被转换为 © 字符。
实体被转换为不间断空格字符,从而提供内联空格。但请注意,因为此字符的不间断方面会将两个元素缝合在一起,这可能会导致奇怪的行为。
Margin
如果您想在元素外部添加空格,请使用 margin
属性。Margin 就像在元素周围添加一个缓冲垫。margin
属性是 margin-top
、margin-right
、margin-bottom
和 margin-left
的简写。
margin
简写以特定顺序应用属性:上、右、下和左。您可以使用“TRouBLe”来记住这些顺序。
margin
简写也可以与一个、两个或三个值一起使用。添加第四个值可以让您设置每个单独的边。这些值的应用方式如下:
- 一个值将应用于所有边。(
margin: 20px
)。 - 两个值:第一个值将应用于顶部和底部边,第二个值将应用于左侧和右侧边。(
margin: 20px 40px
) - 三个值:第一个值是
top
,第二个值是left
和right
,第三个值是bottom
。(margin: 20px 40px 30px
)。
Margin 可以使用长度、百分比或 auto 值定义,例如 1em
或 20%
。如果您使用百分比,该值将根据元素包含块的宽度计算。
这意味着如果您的元素包含块的宽度为 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
的间距,因为 2rem
和 3rem
加起来计算为 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,那么它们之间将有多少空间?
阻止 margin 折叠
如果您将元素设置为绝对定位,使用 position: absolute
,则 margin 将不再折叠。如果您也使用 float
属性,margin 也不会折叠。
如果您在两个具有块 margin 的元素之间有一个没有 margin 的元素,则 margin 也不会折叠,因为两个具有块 margin 的元素不再是相邻的同级元素:它们只是同级元素。
在布局课程中,您学习了 flexbox 和 grid 容器与块容器非常相似,但处理其子元素的方式却大相径庭。margin 折叠也是如此。
如果我们采用课程中的原始示例并应用列方向的 flexbox,则 margin 会组合而不是折叠。这可以为布局工作提供可预测性,而这正是 flexbox 和 grid 容器的设计目的。
Margin 和 margin 折叠可能很难理解,但详细了解它们的工作原理非常有用,因此强烈建议阅读这份详细的解释。
Padding
与 margin
在框外部创建空间不同,padding
属性在框的内部创建空间:就像隔热层一样。
根据您使用的盒模型(在盒模型课程中介绍过),padding
也会影响元素的整体尺寸。
padding
属性是 padding-top
、padding-right
、padding-bottom
和 padding-left
的简写。与 margin
一样,padding
也具有逻辑属性:padding-block-start
、padding-inline-end
、padding-block-end
和 padding-inline-start
。
定位
在布局模块中也介绍过,如果您为 position
设置的值不是 static
,则可以使用 top
、right
、bottom
和 left
属性来分隔元素。这些方向值在行为方式上存在一些差异:
- 即使您设置这些值,具有
position: relative
的元素也会保持其在文档流中的位置。它们也将相对于您元素的位置。 - 具有
position: absolute
的元素将根据相对父元素的位置确定方向值。 - 具有
position: fixed
的元素将根据视口确定方向值。 - 具有
position: sticky
的元素仅在其停靠/粘滞状态下应用方向值。
在逻辑属性模块中,您学习了 inset-block
和 inset-inline
属性,它们允许您设置遵循书写模式的方向值。
这两个属性都是组合 start
和 end
值的简写,因此接受一个值来设置为 start
和 end
,或者接受两个单独的值。
Grid 和 flexbox
最后,在 grid 和 flexbox 中,您都可以使用 gap
属性在子元素之间创建空间。gap
属性是 row-gap
和 column-gap
的简写,它接受一个或两个值,可以是长度或百分比。您也可以使用关键字,例如 unset
、initial
和 inherit
。如果您仅定义一个值,则相同的 gap
将应用于行和列,但是如果您定义了两个值,则第一个值是 row-gap
,第二个值是 column-gap
。
对于 flexbox 和 grid,您还可以使用其分布和对齐功能来创建空间,我们在grid 模块和flexbox 模块中对此进行了介绍。
创建一致的间距
选择一种策略并坚持使用它,以帮助您创建具有良好流动性和节奏的一致用户界面,这是一个非常好的主意。实现此目的的一个好方法是为您的间距使用一致的度量标准。
例如,您可以承诺使用 20px
作为元素之间所有间隙(称为 gutters)的一致度量标准,以便所有布局看起来和感觉一致。您也可以决定使用 1em
作为流内容之间的垂直间距,这将基于元素的 font-size
实现一致的间距。无论您选择什么,都应将这些值另存为变量(或 CSS 自定义属性)以标记这些值,并使一致性更容易实现。
:root {
--gutter: 20px;
--spacing: 1em;
}
h1 {
margin-left: var(--gutter);
margin-top: var(--spacing);
}
像这样使用自定义属性允许您定义一次,然后在整个 CSS 中使用它们。当它们更新时(在元素本地或全局范围内),这些值将通过层叠传递下去,并且更新后的值将得到反映。
检查您的理解情况
测试您对间距的知识
在以下情况下,可以安全地使用 HTML 进行间距...
要在框内部创建空间,请使用...
要在框外部创建空间,请使用...
要在框之间创建空间,请使用...