原文: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
布局与如今在浏览器中常见的其他布局会有所不同。例如 Flexbox
和 Grid
,获取容器元素中子元素,让这些子元素参与到 flex
和 grid
的布局中来。使用 multicol
,在每一列的内部,您还可以获得正常的内容流。
在下面的例子中,我们正在使用 column-width
,最小列宽为 14em
。Multicol
会尽可能多的分配宽度为 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 Media
,multicol
和处于停滞状态的区域样式 (Region Styling); 区域也会支持展示被分解(碎片化)连续的内容。通过使用这些通用属性,它们可以应用于任何未来的CSS 片段模块 上下文,就像 Flexbox
的对齐属性被移动到 Box Alignment
规范中一样,以便它们可以在 Grid
和 Block
布局中使用。
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-
属性还可以用作 Grid
和 Flex
布局的备选方案。如果在容器上指定其中一个属性,则使用 display: flex
或 display: grid
将删除任何列行为,将该容器转换为 Flex
或 Grid
布局。例如,如果你有一个使用 Grid
布局的卡片布局,如果它在列中而不是在页面上运行,那么布局就是可读的,你可以使用 multicol
作为简单的后备。不支持 Grid
的浏览器将获得 multicol
显示,支持 Grid
的浏览器将获得 Grid Layout
。
别忘了 Multicol!
我经常回答 Grid
和 Flexbox
的问题,答案是不使用 Grid
或 Flexbox
,而是试试 Multicol
。您可能不会在每个站点上使用它,但是当您遇到本文中提到的场景时,它可能非常有用。在 MDN 上有关于 multicol 和 CSS 片段模块的有用资源。
如果您在项目中有 multicol
的其他使用场景,也欢迎留言分享!
本文已经联系原文作者,并授权翻译,转载请保留原文链接