乐趣区

译如何以及何时使用CSS多列布局

原文:When And How To Use CSS Multi-Column Layout
作者:Rachel Andrew
译者:博轩

当我们把注意力都放在 CSS Grid 布局和 CSS Flexbox 布局的时候,经常忽略了另一种布局方法。在本文中,我将介绍 多列布局 – 通常称为 multicol 或者 “CSS Columns”。通过这篇文章,你了解到使用 columns 的最佳实践,以及一些使用 columns 的注意事项。

什么是 Multicol?

multicol 的基本思想是,你可以把一大块内容带到多个列中,就像报纸一样。您可以使用两个属性中的其中一个来完成此操作。您可以使用 cloumn-count 属性来指定内容的列数。还可以使用 column-width 属性来指定理想的列宽,让浏览器来决定合适的列数。

不论你的内容包含什么样的元素,当你将它转换为多列布局时,一切都将保持正常的内容流,但是将以列的形式展现。这使得 multicol 布局与如今在浏览器中常见的其他布局会有所不同。例如 FlexboxGrid,获取容器元素中子元素,让这些子元素参与到 flexgrid 的布局中来。使用 multicol,在每一列的内部,您还可以获得正常的内容流。

在下面的例子中,我们正在使用 column-width,最小列宽为 14emMulticol 会尽可能多的分配宽度为 14em 的列,然后,让每一列分享剩余的空间。每一列的宽度至少 14em,除非,容器的宽度小于 14em,那么将只展示一列。multicol 也是 CSS 中首次出现的一种行为,可以创建出列,同时也默认符合响应式的规则。您不必增加 CSS 查询条件 (Media Queries),修改每一个断点的列数,而是制定一个最佳的宽度,让浏览器自身来进行处理。

示例链接

// 核心代码摘录
.container {
  max-width: 800px;
  margin: 0 auto;
  column-width: 14em;
}

列样式

当你使用列属性(columns)来创建布局的时候,cloumns box 中的内容将无法定位。您无法使用 JavaScript 来进行定位,您也无法为单个列来指定唯一的样式,比如背景颜色,外边距,内边距等等。所有 column boxes 将保持相同的大小。你唯一可以做的事情,就是使用 column-rule 属性来添加列之间的规则,该属性的作用类似于 border。您还可以使用 column-gap 属性控制列之间的间隙,该属性的默认值为 1em,但是您还可以将其改为任何有效的长度单位。

示例链接

// 核心代码
.container {
  max-width: 800px;
  margin: 0 auto;
  column-width: 14em;
  column-gap: 2em;
  column-rule: 1px solid #ccc;
}

这是 multicol 的基本功能。您可以将一大块内容拆分为列。内容将依次填充到每一列,并在内联的方向创建这些列。您可以控制列之间的间隙以及规则,使用与 border 相同的取值即可。到目前为止,上述所有内容在浏览器中得到了很好的支持,并且已经存在了很长时间,使得这个规范在向后兼容性方面非常安全。

您可能需要考虑使用列的其他一些事项,以及在 Web 上使用列时需要注意的一些潜在问题。

跨栏

有时候,您可能希望将某些内容分解为列的同时,使用一个元素跨越这些列。将 columns-span 属性用于 multicol 可以实现这一点。

下面的示例中,我使用一个 <blockquote> 元素来跨越列。请注意,在执行此操作时,内容会被分为两个区域,分别位于设置了 column-span 元素的上下两个部分。内容不会跳过设置了 column-span 的元素。

column-span 属性目前已在 Firefox 中实现,并且向后兼容。

示例链接

// 核心代码
blockquote {
  font: 2em 'Berkshire Swash', cursive;
  margin: 0;
  column-span: all;
  text-align: center;
}

.container {
  max-width: 800px;
  margin: 0 auto;
  column-width: 14em;
  column-gap: 2em;
  column-rule: 1px solid #ccc;
}

要知道,目前的规范,column-span 的取值只有 all 或者 none。如果你想实现报纸中的样式,可以使用多列布局结合其他布局来实现。在下面的示例中,我们实现了一个带有两个列轨道的网格容器(Grid)。左边轨道的宽度是 2fr,右边轨道的宽度是 1fr。我们将左边的轨道变成了一个具有两栏的 multicol 容器。它同样包含了一个跨栏元素。

在右边,我们将内容放入第二个 Grid 列轨道中。通过尝试各种布局方法,我们可以确切地找出适合手头工作的布局方法 – 不要害怕混合搭配!

示例链接

// 核心代码
.container {
  max-width: 800px;
  margin: 0 auto;
  display: grid;
  grid-gap: 1em;
  grid-template-columns: 2fr 1fr;
  align-items: start;
}

.container article {
  column-count: 2;
  column-gap: 2em;
  column-rule: 1px solid #ccc;
}

.container aside {
  border-left: 1px solid #ccc;
  padding: 0 1em;
}

控制内容截断

如果您的内容中包含标题,您可能希望避免标题出现在列的末端,而内容却出现在了下一列中。再比如,您的内容中有一些带有文字说明的图片,那么理想的情况下,图片和他的文字说明,将保持一个整体展示,而不会被跨列分割。

当您将内容拆分为列时,这种行为被称为CSS 片段模块(Fragmentation)。将内容分割成两页进行展示,就好像打印机选择两栏的打印模式一样。因此,相比较 Web 上的其他布局方法,multicol 是最接近Paged Media 的布局方法。因此,我们可以使用属于 CSS2.1 的属性 page-break 来实现这一点。

  • page-break-before
  • page-break-after
  • page-break-inside

最近,CSS 片段模块 规范定义了如何为各种片段模块上下文设计的碎片化的属性,规范包括 Paged Mediamulticol 和处于停滞状态的区域样式 (Region Styling); 区域也会支持展示被分解(碎片化)连续的内容。通过使用这些通用属性,它们可以应用于任何未来的CSS 片段模块 上下文,就像 Flexbox 的对齐属性被移动到 Box Alignment 规范中一样,以便它们可以在 GridBlock 布局中使用。

  • break-before
  • break-after
  • break-inside

下面的示例中,我在 <figure> 元素中使用 break-inside avoid 属性,防止图像的标题和图像分离。支持该属性的浏览器中,我们应该可以看到联合在一起的效果,即使这会导致列中的内容看起来不平衡。

示例链接

// 核心代码

figure {
  margin: 0;
  break-inside: avoid;
}

.container {
  max-width: 800px;
  margin: 0 auto;
  column-width: 14em;
}

不幸的是,在 multicol 中对这些属性的支持非常不完整。即使在支持的情况下,它们也应该被视为一个建议,因为在实际使用的时候,会提出很多要求来控制内容是否应该被分离,但是实际上浏览器并不会真正让这些内容分离。在上面的示例中,我们定义了展示的优先级,但是当您在使用的时候还是要谨慎一些,仅在最需要的地方使用。

Columns 布局的一些问题

我们在浏览网页时,并没有看到 multicol 被广泛的使用,其原因是读者的阅读习惯,通常是自顶向下滚动阅读的。对于使用英语,或其他垂直写作的人来说,横向的布局并不是很好的阅读体验。

如果你固定容器的高度,例如使用 viewport 单位 vh,当内容过多时,它会在内联方向溢出,同时,你会得到一个横向的滚动条。

示例链接

这些情况都不是很理想。所以,在使用多列布局的时候,我们需要仔细的考虑每一栏的内容量。

Columns 块溢出

Level 2 的规范当中,我们考虑如何使用一种方法,列的内容不会溢出,生成横向的滚动条,而是在块的方向上面生成新的列。这意味着您可以拥有一个具有高度的 multicol 容器,并且一旦内容超出了该容器的宽度,就会在下面创建一组新的列。这看起来有点像我们上面的跨越示例,但是,不是让设置了 column-span 的元素导致新的列框开始,而是由块大小限制的容器宽度,从而解决溢出的问题。

此功能将使 multicol 对 Web 更有用。虽然我们现在还有一段距离,但您可以关注 CSS 工作组回购中的问题。如果您有此功能的其他用例,请发布它们,它在设计新功能时非常有用。

今天,我们该如何使用 Multicol ?

使用当前规范,不建议将所有内容拆分为列而不考虑滚动问题。但是,在某些情况下,multicol 对于 web 是理想的。在查看设计模式时,有足够的示例 k 可供你参考。

折叠小 UI 或文本元素

multicol 可以在任何需要占用较少空间的项目列表的地方使用。例如,复选框的简单列表或名称列表。通常在这些情况下,访问者不会读取一列然后返回到下一列的顶部,而是扫描内容以选中要单击的复选框或要选择的项目。即使您确实创建了滚动体验,这个问题也依然存在。

您可以在 DonarMuseum 网站 上看到 Sander de Jong 以这种方式使用的 multicol 示例。

确认的少量内容

有时,我们设计一个网站,我们知道某些内容区域相对较小,并且适合大多数屏幕展示,且不需要滚动。我在 https://noti.st/rachelandrew/Au3wK3/making-things-better-redefining-the-technical-possibilities-of-css 使用了 multicol,用于介绍演讲。

Andy Clarke 为 Equfund 网站设计了一个可爱的例子。

为了避免非常小的屏幕导致页面出现滚动,就像宽度一样,您可以使用媒体查询来检查高度。对于超出最小高度的内容,您可以在断点处设置 min-height,来避免用户使用较小设备时所带来的较差体验。

瀑布流(MASONRY-LIKE)的内容显示

多列布局工作得很漂亮的另一个地方是,如果要创建瀑布流的内容显示。Multicol 是目前唯一一种,可以创建不定高度的布局方法。Grid 布局要么会留下间隙,要么拉伸项目以形成严格的二维网格。

Veerle Pieters 有一个很好的例子,就是在她的灵感页面上以这种方式使用multicol

Grid 和 Flexbox 的备选方案

这些 column- 属性还可以用作 GridFlex 布局的备选方案。如果在容器上指定其中一个属性,则使用 display: flexdisplay: grid 将删除任何列行为,将该容器转换为 FlexGrid 布局。例如,如果你有一个使用 Grid 布局的卡片布局,如果它在列中而不是在页面上运行,那么布局就是可读的,你可以使用 multicol 作为简单的后备。不支持 Grid 的浏览器将获得 multicol 显示,支持 Grid 的浏览器将获得 Grid Layout

别忘了 Multicol!

我经常回答 GridFlexbox 的问题,答案是不使用 GridFlexbox,而是试试 Multicol。您可能不会在每个站点上使用它,但是当您遇到本文中提到的场景时,它可能非常有用。在 MDN 上有关于 multicol 和 CSS 片段模块的有用资源。

如果您在项目中有 multicol的其他使用场景,也欢迎留言分享!

本文已经联系原文作者,并授权翻译,转载请保留原文链接

退出移动版