您可能已经了解 CSS gap
属性。它并不完全是新的,但它在去年获得了重要的全新功能:它现在除了 CSS Grid 之外,还在 Flexbox 中起作用。这一点,以及我认为该属性比看起来更复杂的事实,让我想要回顾并准确解释它的工作原理。
让我们仔细看看 gap
及其关联的属性,并了解它们如何以及在何处工作。
所有间隙属性
首先,让我们回顾一下与 gap
相关的所有 CSS 属性。总共有六个。
grid-row-gap
grid-column-gap
grid-gap
row-gap
column-gap
gap
从这个列表中,我们可以忽略前三个属性。grid-*
属性是在 CSS Grid 规范起草初期添加的,后来在 gap
变得更通用时被弃用。浏览器仍然支持这些被弃用的 grid-*
属性(截至本文撰写时),并且仅仅将它们视为不存在 grid-
前缀。因此,grid-gap
与 gap
相同,grid-column-gap
与 column-gap
相同,grid-row-gap
与 row-gap
相同。
至于其他三个属性,知道 gap
是一个简写,允许您指定其他两个属性,我们实际上只需要知道 row-gap
和 column-gap
的作用。
我们对这些属性的理解取决于我们使用的 CSS 布局类型。让我们首先看看这些选项。
间隙可以在哪里使用?
如果您像我一样,您已在网格布局中使用过间隙,但它们现在也可以在 Flexbox 以及多列布局中使用。让我们回顾一下每种情况。
网格间隙
所有浏览器都支持网格布局中的间隙,并且在这种情况下,它们非常容易理解。
row-gap
在行轨道之间引入空间。column-gap
在列轨道之间引入空间。

让我们创建一个具有三列和两行的网格。
.container {
display: grid;
grid-template-columns: 200px 100px 300px;
grid-template-rows: 100px 100px;
}
这给了我们以下网格。

上图中的线称为**网格线**,它们分隔网格的轨道(行和列)。这些线在网格中并不真正存在——它们是不可见的,没有厚度,并且通常是当我们启用网格检查器时(在 Safari、Firefox、Edge 或 Chrome 中)DevTools 显示的内容。

但是,如果我们开始向网格添加间隙,它就会像这些线开始获得厚度一样工作。
让我们添加一个 20px
的间隙。
.container {
display: grid;
grid-template-columns: 200px 100px 300px;
grid-template-rows: 100px 100px;
gap: 20px;
}
我们轨道之间的线现在有 20px
厚,因此将网格项推得更远。

值得注意的是,轨道仍然具有相同的大小(由 grid-template-*
属性定义);因此,网格比没有间隙时更宽更高。
在网格中,row-gap
始终应用于行轨道之间。因此,如果我们在上面的示例中用 row-gap
替换 gap
,我们将得到以下结果。

而 column-gap
始终应用于列轨道之间,因此用 column-gap
替换 gap
会产生以下结果。

网格很简单,因为默认情况下,列是垂直的,行是水平的,就像表格一样。因此,很容易记住 column-gap
和 row-gap
应用的位置。
现在,当使用 writing-mode
时,事情会变得稍微复杂一些。网络上的默认书写模式是水平的,从左到右,但也有垂直书写模式,当这种情况发生时,列变为水平,行变为垂直。始终注意 writing-mode
,因为它可能使其不那么直观。
这是一个很好的过渡到下一部分,因为列和行在 Flexbox 中获得了新的含义。
Flexbox 间隙
让我们谈谈 Flexbox 布局中的间隙,事情变得有点复杂。我们将使用以下示例。
.container {
display: flex;
}
默认情况下,这会给我们一个 row
flex 容器,这意味着容器内的项目从左到右堆叠在同一水平线上。

在这种情况下,column-gap
应用于项目之间,而 row-gap
没有任何作用。这是因为只有一行(或一行)。但现在让我们在项目之间添加一些间隙。
.container {
display: flex;
column-gap: 10px;
}

现在让我们将容器的 flex-direction
切换到 column
,它将项目垂直堆叠,从上到下,使用以下代码。
.container {
display: flex;
flex-direction: column;
column-gap: 10px;
}
以下是发生的情况。

间隙消失了。即使 column-gap
在容器处于 row
方向时确实在项目之间添加了空间,但在 column
方向上它也不再起作用。
我们需要使用 row-gap
来取回它。或者,我们可以使用带有单个值的 gap
简写,这将在两个方向上应用相同的间隙,因此在两种情况下都能工作。
.container {
display: flex;
flex-direction: column;
gap: 10px;
}

因此,概括地说,colum-gap
始终垂直工作(假设默认的 writing-mode
),而 row-gap
始终水平工作。这并不依赖于 flex 容器的方向。
但现在看看一个包含换行符的示例。
.container {
display: flex;
flex-wrap: wrap;
column-gap: 40px;
row-gap: 10px;
justify-content: center;
}
在这里,如果在一行中没有足够的空间来容纳所有内容,我们允许项目使用 flex-wrap: wrap
换行。

在这种情况下,column-gap
仍然垂直应用于项目之间,row-gap
水平应用于两个 flex 行之间。
这与网格之间有一个有趣的区别。列间隙不一定会跨 flex 行对齐。这是因为 justify-content: center
,它将项目在其 flex 行内居中。这样,我们可以看到每条 flex 行都是一个独立的布局,其中间隙独立于其他行应用。
多列间隙
多列 是一种布局类型,它使内容在多列之间自动流动变得非常容易,就像您在传统的报纸文章中所期望的那样。我们设置列数并设置每列的大小。

多列布局中的间隙与网格或 Flexbox 的工作方式略有不同。有三个显着的差异。
row-gap
没有效果。column-gap
具有非 0 的默认值。- 并且间隙可以设置样式。
让我们分解一下。首先,row-gap
没有效果。在多列布局中,没有行需要分隔。这意味着只有 column-gap
是相关的(gap
简写也是如此)。
其次,与网格和 Flexbox 不同,column-gap
在多列布局中具有 1em
的默认值(而不是 0)。因此,即使根本没有指定间隙,内容的列仍然会视觉上分隔开来。当然可以覆盖默认间隙,但这是一个很好的默认值。
以下是示例所依据的代码。
.container {
column-count: 3;
padding: 1em;
}
最后,我们可以在多列布局中设置列之间空隙的样式。我们使用 column-rule
属性,它类似于 border
。
.container {
column-count: 3;
column-gap: 12px;
column-rule: 4px solid red;
padding: 12px;
}

column-rule
属性在多列布局中为我们提供了一些样式功能。浏览器支持
gap
在各方面都得到了很好的支持。在 caniuse 上有更多信息,但概括地说。
- Flexbox:
gap
在所有地方都受支持,除了 Internet Explorer(它 即将推出)、Opera Mini 和 UC Browser for Android。 caniuse 的全球支持率为 87.31%。 - Grid:同样,但我们查看的是 93.79% 的全球支持率。
- 多列:同样,它在 Safari 中不受支持,并且 全球支持率为 75.59%。
因此,总的来说,gap
属性得到了很好的支持,并且在大多数情况下,不需要变通方法。
设置 flex 和 grid 中间隙的样式
在 Flexbox 和 CSS Grid 中使用 gap
进行样式设置将非常有用。不幸的是,目前还没有任何浏览器支持它。但好消息是,它可能在不久的将来实现。这已经在 CSS 工作组中进行了讨论,并且 Firefox 正在开发中。一旦 Firefox 拥有一个可工作的实现以及规范提案,它可能会推动其他浏览器也进行实现。
在此期间,有一些解决方法。
一种方法是给网格容器设置一个背景颜色,然后给项目设置不同的颜色,最后设置间隙以使容器颜色显示出来。
虽然这种方法有效,但意味着我们无法使用间隙在项目之间引入空格。这里的 gap
充当边框宽度。因此,为了更直观地分隔项目,我们需要在项目上使用 padding
或 margin
,但这并不理想……正如我们将在下一节中看到的那样。
我不能只使用 margin 或 padding 吗?
是的,在大多数情况下,我们也可以使用 margin(和/或 padding)在布局元素之间添加视觉空间。但是 gap
具有多种优势。
首先,间隙是在容器级别定义的。这意味着我们为整个布局定义它们一次,并且它们在布局中一致地应用。使用 margin 需要在每个项目上进行声明。当项目性质不同或来自不同的可重用组件时,这可能会变得复杂。
最重要的是,间隙默认情况下只需一行代码即可正确执行。例如,如果我们试图在弹性项目之间引入一些空间,而不是围绕它们,margin
将需要特殊情况来 移除第一个项目之前的额外 margin 和最后一个项目之后的额外 margin。使用间隙,我们不需要这样做。
如果在每个弹性项目上使用 margin: 0 20px
,我们将得到以下结果

但是,如果在容器上使用 gap: 40px
,我们将得到以下结果

类似地,在网格布局中,在容器级别定义 gap
比必须在每个项目上定义 margin 并考虑应用于网格边缘的 margin 简单得多,并且提供了更好的结果。
如果在每个网格项目上使用 margin: 20px

如果在网格容器上使用 gap: 40px

空白空间累加
结合前面所说的内容,margin
和 gap
不必是互斥的。实际上,有许多方法可以将布局的项目进一步分隔开,并且它们都可以很好地协同工作。
gap
属性只是布局容器中盒子之间创建的空白空间的一部分。margin
、padding
和对齐方式都可能会增加 gap
已定义的空白空间。
让我们考虑一个示例,其中我们构建一个简单的弹性布局,具有给定的宽度、一些间隙、一些内容分布(使用 justify-content
)以及一些 margin 和 padding。
.container {
display: flex;
gap: 40px;
width: 900px;
justify-content: space-around;
}
.item {
padding: 20px;
margin: 0 20px;
}
假设这段代码产生以下结果

现在,让我们准确地了解项目之间的空白空间是如何创建的

如我们所见,两个连续的弹性项目之间有四种不同类型的空白空间
- 在两个连续的项目之间,间隙定义了这些项目之间的最小空间。可以有更多空间,就像在本例中一样,但永远不能有更少的空间。
- Margin 将项目进一步分隔开,但与
gap
不同,它在所有项目的两侧都添加了空间。 - Padding 在每个项目内部提供一些空间。
- 最后,并且仅当有足够的剩余空间时,内容分布才会生效,并根据
space-around
值在弹性行中均匀地分布项目。
调试间隙
最后,让我们来讨论一个对我来说非常重要的话题:用于调试间隙的 DevTools 支持。总有一些情况会出现问题,并且知道 DevTools 可以为我们提供支持非常令人欣慰,但我们需要知道在这种情况下哪些工具可以帮助我们。
对于 gap
,我可以想到两个可能非常有用的特定功能。
我的间隙是否处于活动状态?
除非我们拼写错误 gap
或提供了无效的值,否则该属性将始终应用于页面。例如,这是正确的
.some-class {
display: block;
gap: 3em;
}
它不会做任何事情,但它是有效的 CSS,并且浏览器并不介意 gap
不适用于块级布局。但是,Firefox 具有一个名为 Inactive CSS 的功能,它正是这样做的:它关心应用于有意义的事物的有效 CSS。在这种情况下,Firefox DevTools 会在检查器中显示警告。

我的间隙在哪里?
Chrome 和 Microsoft Edge 也具有一个非常有用的调试间隙的功能。它是通过微软和谷歌之间的合作添加的,旨在在 Chromium(为这两个浏览器以及其他浏览器提供支持的开源项目)中构建布局调试工具。在这些浏览器中,您可以将鼠标悬停在“样式”面板中的各个属性上,并查看它们对页面的影响。

gap
和 justify-content
属性上,页面上的相应区域会亮起,以指示这些属性在哪里生效。
margin
和 padding
属性上,这将突出显示页面相应的盒子模型区域。就是这样。我希望本文有助于理解 CSS 中间隙工作原理的一些细节。
我想指出,flex gap 仅在 Safari 14.1 中受支持,因此我认为使用它并不安全,我们应该使用 grid gap 或一些技巧。
是的,我一直以为 flex 中的 gap 在 Safari 中也能工作。14.1 仅在 2021 年 4 月发布,我个人认为它是一个“也许明年我们会使用它”的功能。很高兴它终于正式得到支持了!
不知道列也使用 gap 属性,这很不错!不过同样,Safari 唉