阅读 453

【翻译】css中的“gap”

你可能已经了解过CSS gap property。 准确来说它并不是一个全新的css属性,但是去年它获得了一个重要的特性:除在了CSS Grid中,在Flexbox中也能使用。我相信这个属性比它表面呈现的更复杂,这也让我想回去解释一下它到底是如何运行的。

让我们仔细看看gap和它的相关属性,并了解它们是怎样生效的以及哪些地方能生效。

关于间隙(gap)的所有属性

首先,让我们回顾一下所有gap相关的CSS properties。一共有6个:

  • grid-row-gap

  • grid-column-gap

  • grid-gap

  • row-gap

  • column-gap

  • gap

我们可以忽略这个列表中的前三项,grid-*属性是在CSS Grid规范拟定早期加入的,在gap普遍使用后便被废弃了。浏览器仍然支持这些废弃的grid-*属性(在撰写本文时),并且处理这些属性时忽略grid-前缀。因此,grid-gap 等同于 gapgrid-column-gap 等同于 column-gap , grid-row-gap 等同于 row-gap

至于另外的三个属性,只要知道gap是其他两个属性的缩写,我们实际上只需要了解row-gapcolumn-gap的作用。

对这些属性的理解要基于我们使用的CSS布局类型。让我们先看看这些选项。

在哪些地方可以使用gaps?

你可能和我一样,仅在grid布局中使用过gaps,但是他们现在可以在Flexbox以及多列布局中使用。让我们看看这每种案例。

Grid gaps

所有浏览器都支持在grid布局中使用gaps,在这种context中理解它们非常容易。

  • row-gap 在行间中引入空隙

  • column-gap 在列间中引入空隙

image.png

让我们创建一个三列两行布局:

.container {
  display: grid;
  grid-template-columns: 200px 100px 300px;
  grid-template-rows: 100px 100px;
}复制代码

我们获得了如下网格:

image.png

图中的线叫做网格线grid lines,它们将网格分割为行和列。这些网格线并不真实存在——它们是不可见的,没有宽度的,并且通常是我们开启grid inspector后DevTools展示的。 (in Safari, Firefox, Edge or Chrome).

The CSS-Tricks site with DevTools open and docked to the left of the viewport in Firefox. DevTools displays Grid Inspector options and the page contains borders around elements in blue and green to indicate grid track lines.

然而如果我们开始为网格增加gaps,它将表现得好像这些网格线获得了宽度一样。

让我们增加 20px gap:

.container {
  display: grid;
  grid-template-columns: 200px 100px 300px;
  grid-template-rows: 100px 100px;
  gap: 20px;
}复制代码

现在行列间的网格线是20px宽,因此grid items彼此被推得更远了。

A 3 by 2 grid of yellow boxes with 20px gaps between the column and row tracks.

值得注意的是,网格块们仍然有着同样的大小(由 grid-template-*定义),因此整个网格会比没有gaps更宽更高。 在网格内,row-gap始终应用于行块间,因此在上面的例子中,如果我们将gap替换为 row-gap,将得到如下示例:

The same 3 by 2 grid with a gap only between the two rows.column-gap始终应用于列块间,因此如果将gap 替换为 column-gap将会得到如下结果:

The same 3 by 2 grid with a gap only between the three columns.Grid布局很简单,因为默认情况下列(columns)是垂直的,而行(rows)是水平的,就像在table中。因此很容易记住column-gap 和 row-gap是用在哪里的。

现在,事情变得稍微复杂了一点点,由于我们使用了writing-mode。在web中默认的书写模式(writing mode)是水平的,从左到右,但是同样有上下的书写模式。在这种模式下列(colums)变成水平的,而行(rows)变成垂直的。 要对writing-mode留个心眼,因为它有时候会反直觉。

这是一个到下一节的很好的过渡,因为在Flexbox中列和行(columns and rows)又有了新的含义。

Flexbox gaps

让我们讲讲Flexbox布局中的gaps,这里会稍微有些小复杂。我们使用如下例子:

.container {
  display: flex;
}复制代码

默认情况下,这会产生一个row flex容器,这意味着容器中的items被从左往右放在了同一个水平线上。

A default flex container with six yellow boxes stacked horizontally, from left to right. Each one says flex item in it. A purple border is drawn around each item.在这个案例中,column-gap 在items间生效,而row-gap啥都不会做。这是因为只有一行。但是我们还是先对items增加一些gap:

.container {
  display: flex;
  column-gap: 10px;
}复制代码

The same six yellow flex items on a single line with 10 pixels between them.现在让我们将容器的flex-direction切换为column,这样items将会从上往下垂直分布,代码如下:

.container {
  display: flex;
  flex-direction: column;
  column-gap: 10px;
}复制代码

效果如下:

Six yellow rectangles stacked from top to bottom with no gap between them.

gap消失了。当container是row横向布局时,column-gap确实在items之间增加了间距,但是在column纵向布局时并不会生效。

我们需要使用row-gap让它再次生效,或者我们可以使用gap缩写,它可以在两个方向上产生同样的gap

.container {
  display: flex;
  flex-direction: column;
  gap: 10px;
}复制代码

The same six yellow rectangles stacked vertically, but with 10 pixels of space between them.

所以,总结一下, 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来允许items换行。

Five yellow boxes that wrap into two lines, where three are on the first line and two are on the bottom line. There are differently sized gaps between them based on the space around them.

在这个例子中,column-gap 仍然在items之间垂直生效,而row-gap 在两个flex行间水平生效。

这和grid布局有一个有趣的不同点。column gaps并不一定跨flex line对齐。这是因为justify-content: center使得items在flex lines中居中了。这样,我们可以看到每个flex line是一个单独布局,而gaps在lines中各自生效。

Multi-column 多列布局的 gaps

多栏布局可以很容易地在多列中自动排列内容,就像你可能在传统报纸文章中看到的那样。我们设置了一些列,并且为每列设置了大小。

A three-column layout of plain text with a 1 em gap between columns

gaps在多栏布局中和在grid或flexbox中的表现大相径庭。有三个显著的区别:

  • row-gap 不会生效,

  • column-gap 默认值不是0,

  • gaps 可以被设置样式.

让我们分解开来。首先,row-gap不会生效。在多栏布局中不会有多行被分隔开,这意味着只有column-gap能起到效果(gap缩写也一样)。

其次,不像在grid和flexbox中,column-gap在多栏布局中的默认值是1em,而不是0,所以即使并没有指定任何gap,列之间仍然可以看到被分开了。当然,默认的gap可以被重写,但是这是一个很好的默认设置。

例子中的代码如下:

.container {
  column-count: 3;
  padding: 1em;
}复制代码

最后,我们可以在多栏布局中为gap设置样式。我们可以使用column-rule属性,它类似 border:

.container {
  column-count: 3;
  column-gap: 12px;
  column-rule: 4px solid red;
  padding: 12px;
}复制代码

The same three columns of plain text, but with a red border between the columns.

column-rule属性在多列布局中给我们提供了一些样式支持。

浏览器支持

gap已经被全面支持。更多信息可见 caniuse,总结如下:

  • Flexbox:  gap is supported everywhere except for Internet Explorer (which is on its way out), Opera Mini and UC Browser for Android. caniuse has global support at 87.31%.

  • Grid:  Same thing, but we’re looking at 93.79% global support.

  • Multi-column:  Same thing, too, but it’s unsupported in Safari and has 75.59% global support.

所以总的来说,gap属性已经得到了很好的支持,在多数情况下并不需要进行变通。

为flex和grid中的gap设置样式

为flexbox和grid中的gap设置样式是很实用的。坏消息是目前这还并不支持,但好消息是在不远的将来将会实现。  CSS 工作组已经在讨论 , Firefox正着手实现。一旦我们在Firefox实现相关的规范提案,兴许会驱动其他浏览器的实现。

与此同时,也有其他的办法解决这个问题。

一个办法是对grid容器设置一个背景色,然后对items设置另一个背景色,最后设置gap让容器的颜色显示出来。

虽然这是可行的,但也意味着我们不能使用gap在item间引入空隙。这里gap表现为边框的宽度。所以为了在视觉上能够更有效地分隔items,我们需要在items上使用padding 或者 margin,这并不优雅...我们将在下一节中看到。

只能用 margin 或者 padding?

是的,在多数情况下,我们可以使用margin(和/或 padding)在元素间增加可见的间隙,但是gap具有很多优势。

首先,gaps是在容器级别定义的间隙,这意味着我们只需要为整个布局定义间隙一次,而它们会在容器中表现一致。使用margins需要在每个item上声明,当items并不一样或来自于不同的复用组件时,这么做可能会变得复杂。

此外,默认情况下gaps只需要一行代码就可以完成正确的事情。例如,如果我们尝试在flex items之间(in between)引入间隙,而不是周围(around),margin在一些特殊场景下可能需要删除第一个或者最后一个元素的多余margin,而用gaps,我们就不需要这么做。

如果对每个flex item使用margin: 0 20px,我们会得到:

然而如果对容器使用 gap: 40px,我们会得到:

在grid布局中也类似,在容器级别上定义 gap比在每个item上定义margin并计算网格边缘的margin要简单和优雅得多。

对每个grid item使用margin: 20px

对grid容器使用gap: 40px

空隙的合计

说了这么多,margin 和 gap 并不是互斥的。事实上,有很多方法可以将布局中的元素进一步分隔开,并且它们能够很好地相互结合。

gap属性只是布局容器中盒子间空隙的一部分,marginpadding,以及对齐都可能增加gap已定义的空隙

让我们考虑这么一个例子,我们创建一个简单的flex布局,并设置宽、gap,使用justify-content分布内容,以及一些margin和padding:

.container {
  display: flex;
  gap: 40px;
  width: 900px;
  justify-content: space-around;
}
.item {
  padding: 20px;
  margin: 0 20px;
}复制代码

我们设想这段代码效果如下:

现在让我们仔细瞧瞧items间的空隙是如何产生的:

正如我们所见,在连续的flex items间,空隙有4种不同的类型:

  • 在两个连续的items间, gap定义了items间的最小间隔,就像在这个案例中展示的,items间的空隙可以再增加,但没法更少。

  • Margin 将items相互推开,但是和gap不同,所有的items两侧都增加了空隙。

  • Padding 在每个item内部提供了一些空隙.

  • 最终,也是因为还有足够的空间剩余, content distribution生效,并根据space-around在flex line内均匀地分配items

Debugging gaps

让我们以一个我非常喜欢的话题来结束:DevTools支持对gaps的debug。总会有出现问题的时候,DevTools的支持是令人欣慰的,但我们确实需要知道在这种情况下哪些工具可以帮助我们。

对于gap,我能想到两个特殊的特性可能有用。

我的gap生效了吗?

除非我们拼错了gap,或者提供了一个非法的值,这个属性将始终应用于页面,例如,这是正确的:

.some-class {
  display: block;
  gap: 3em;
}复制代码

它并不会产生任何效果,但是这是合法的CSS,并且浏览器并不介意 gap并不会在block布局中生效。但是Firefox有个Inactive CSS的特性:关注合法且有意义的CSS。在这个场景下,Firefox DevTools会在 Inspector显示一个警告。

Where is my gap?

Chrome和Edge也有个非常有用的功能来调试gaps。它是通过Microsoft和Google的合作,旨在在Chromium(是支持这两种浏览器以及其他浏览器的开源项目)构建布局调试工具。在这些浏览器里,你可以将鼠标悬停在 Styles panel里的各个属性上,然后你就可以看到它们在页面上的效果。

光标目前悬停在gap 和 justify-content 属性上,页面上的相关区域会高亮显示这些属性的生效了。

光标悬停在 margin 和 padding属性上,并将盒子模型的相关区域高亮。

最后,我希望这篇文章对理解在CSS中gaps如何生效的一些细节能有所帮助。


作者:布列瑟农的星空
链接:https://juejin.cn/post/7016656649695789064


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐