原文: 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
可以实现这一点。
下面的示例中,我使用一个 元素来跨越列。请注意,在执行此操作时,内容会被分为两个区域,分别位于设置了
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
下面的示例中,我在 元素中使用
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
示例。
确认的少量内容
有时,我们设计一个网站,我们知道某些内容区域相对较小,并且适合大多数屏幕展示,且不需要滚动。我在 Notist演示页面 使用了 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
的其他使用场景,也欢迎留言分享!
本文已经联系原文作者,并授权翻译,转载请保留原文链接