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

已发表: 2022-03-10
快速总结↬当我们使用 Grid 和 Flexbox 时,多列布局规范经常被忽视。 在这篇文章中,Rachel Andrew 解释了为什么它与其他布局方法不同,并展示了一些有用的模式和站点来很好地展示它。

在所有关于 CSS 网格布局和 Flexbox 的兴奋中,另一种布局方法经常被忽视。 在本文中,我将了解多列布局——通常称为多列或有时称为“CSS 列”。 您会发现它适合哪些任务,以及制作专栏时需要注意的一些事项。

什么是多列?

multicol 的基本思想是,您可以获取大量内容并将其流入多个列中,就像在报纸中一样。 您可以使用两个属性之一来执行此操作。 column-count属性指定您希望内容分成的列数。 column-width属性指定了理想的宽度,让浏览器确定可以容纳多少列。

将内容中的哪些元素变成多列容器并不重要,一切都保持正常流程,但分为列。 这使得 multicol 不同于我们今天在浏览器中使用的其他布局方法。 例如,Flexbox 和 Grid,获取容器的子元素,然后这些项目参与 flex 或网格布局。 使用 multicol,除了在列内,您仍然可以正常流动。

在下面的示例中,我使用column-width来显示至少14em的列。 Multicol 分配尽可能多14em列,然后在列之间共享剩余空间。 列将至少为14em ,除非我们只能显示一列,在这种情况下它可能会更小。 Multicol 是我们第一次在 CSS 中看到这种行为,默认情况下创建的列本质上是响应式的。 您不需要添加媒体查询并更改各种断点的列数,而是我们指定一个最佳宽度,浏览器会解决它。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:column-width。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:column-width。
跳跃后更多! 继续往下看↓

样式列

无法定位使用某一列属性时创建的列框。 您无法使用 JavaScript 解决它们,也无法为单个框设置样式以赋予其背景颜色或调整填充和边距。 所有列框的大小都相同。 您唯一能做的就是在列之间添加一条规则,使用 column-rule 属性,它的作用类似于边框。 您还可以使用column-gap属性控制列之间的间隙,该属性的默认值为1em ,但是您可以将其更改为任何有效的长度单位。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:列样式。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:列样式。

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

您可能还需要对您的栏目进行进一步考虑,以及在网络上使用栏目时需要注意的一些潜在问题。

跨越列

有时您可能希望将某些内容分成列,然后使一个元素跨越列框。 将column-span属性应用于 multicol 容器的后代可以实现这一点。

在下面的示例中,我使<blockquote>元素跨越我的列。 请注意,执行此操作时,内容会在 span 上方分成一组框,然后在下方开始一组新的列框。 内容不会跳过跨越的元素。

column-span属性目前正在 Firefox 中实现,并且位于功能标志后面。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:column-span。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:column-span。

请注意,在当前规范中, column-span的值为allnone 。 您不能只跨越某些列,但您可以通过将 multicol 与其他布局方法相结合来获得您可能在报纸上看到的那种布局。 在下一个示例中,我有一个带有两个列轨道的网格容器。 左侧轨道是2fr ,右侧轨道是1fr 。 左侧轨道中的文章我已经变成了一个带有两个轨道的多列容器,它还有一个跨越元素。

在右边,我们有一个侧面进入第二个网格列轨道。 通过尝试我们可用的各种布局方法,我们可以准确地确定哪种布局方法适合手头的工作——不要害怕混搭!

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Smashing Multicol:混合布局方法。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Smashing Multicol:混合布局方法。

控制内容中断

如果您的内容包含标题,那么您可能希望避免标题作为列中的最后一件事而内容进入下一列的情况。 如果您有带有标题的图像,那么理想的情况是图像和标题保持为一个单元,而不是跨列拆分。 为了解决这些问题,CSS 具有控制内容中断位置的属性。

当您将内容拆分为列时,您执行的是所谓的碎片化。 如果在页面之间拆分内容也是如此,例如在为打印上下文创建样式表时。 因此,与网页上的其他布局方法相比,multicol 最接近 Paged Media。 正因为如此,多年来控制内容中断的方法一直是使用 CSS2.1 中的page-break-属性。

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

最近,CSS Fragmentation 规范定义了为任何碎片上下文设计的碎片属性,该规范包括 Paged Media、multicol 和停滞区域规范的详细信息; 区域也会分割一段连续的内容。 通过使这些属性具有通用性,它们可以应用于任何未来的碎片化上下文,就像将 Flexbox 中的对齐属性移到 Box Alignment 规范中一样,以便它们可以在网格和块布局中使用。

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

例如,我在<figure>元素上使用了break-inside avoid ,以防止标题与图像分离。 支持的浏览器应该将图形保持在一起,即使这会导致列看起来不平衡。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:break-inside。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:break-inside。

不幸的是,在 multicol 中对这些属性的支持非常不完整。 即使在受支持的情况下,它们也应该被视为一种建议,因为在尝试控制中断时可能会发出如此多的请求,实际上浏览器实际上无法在任何地方中断。 在这种情况下,规范确实定义了优先级,但是仅控制最重要的情况可能对您更有用。

网络上的列问题

我们在网络上没有看到 multicol 被大量使用的一个原因是这样一个事实,即很容易获得一种让读者在块维度中滚动的阅读体验。 对于我们这些使用英语或其他垂直书写模式的人来说,这意味着垂直上下滚动。 这不是一个好的阅读体验!

如果您固定容器的高度,例如使用视口单元vh ,并且内容过多,则内联方向会发生溢出,因此您会得到一个水平滚动条。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:溢出列。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Multicol:溢出列。

这些东西都不是理想的,在网络上使用 multicol 是我们需要非常仔细地考虑我们可能打算流入我们的列的内容量的事情。

块溢出列

对于规范的第 2 级,我们正在考虑如何启用一种方法,通过该方法,当前最终导致水平滚动条的溢出列可以在块方向上创建。 这意味着您可以拥有一个具有高度的多列容器,并且一旦内容创建了填充该容器的列,就会在下面创建一组新的列。 这看起来有点像我们上面的跨越示例,但是,不是有一个扳手导致新的列框开始,而是由一个在块维度上有限制的容器引起的溢出。

此功能将使 multicol 对网络更加有用。 虽然我们现在还有一点路要走,但您可以关注 CSS 工作组 repo 中的问题。 如果您有此功能的其他用例,请发布它们,它在设计新功能时真的很有帮助。

Multicol 对今天有什么用?

根据当前规范,不建议将所有内容分成列而不考虑滚动问题。 但是,在某些情况下,multicol 在网络上是理想的。 在查看设计模式时,有足够多的用例使其成为您应该考虑的事情。

折叠小型 UI 或文本元素

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

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

名称在 DonarMuseum 网站上排列成多个列
在 DonarMuseum 上,我们可以看到 multicol 用于显示名称列表。 (图片来源)(大预览)

已知的少量内容

有时我们在设计一个网站时,我们知道某些内容相对较小,并且适合大多数屏幕而不会导致不必要的滚动。 我在 Notist 演示页面上使用了 multicol,作为演讲的介绍。

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

包含各种内容的两列布局
在 Equfund 网站上,您可以看到不同的 HTML 元素在列内显示时如何保持正常流动。 (图片来源)(大预览)

为了避免非常小的屏幕导致滚动的可能性,请记住您可以使用媒体查询来检查高度和宽度(或者在逻辑世界中,块和内联)。 如果您只在一个断点启用列,该断点的min-height足以容纳其内容,这可以节省滚动体验很差的非常小的设备的用户。

砌体式的内容显示

多列布局可以很好地工作的另一个地方是,如果你想创建一个砌体类型的内容显示。 Multicol 是目前唯一可以创建这种高度不等的布局的布局方法。 网格要么留下空隙,要么拉伸项目以形成严格的二维网格。

Veerle Pieters 在她的灵感页面上有一个以这种方式使用 multicol 的漂亮例子。

由 Veerle Pieters 设计的列中多个盒子的排列
在 Veerle Pieters 的这个设计中,multicol 用于将多个框或卡片布局为列。 (大预览)

Grid 和 Flexbox 后备

column-属性也可以用作 Grid 和 Flex 布局的后备。 如果您在容器上指定其中一个属性,则使用display: flexdisplay: grid将该容器转换为 Flex 或 Grid 布局,任何列行为都将被删除。 例如,如果您有一个使用网格布局的卡片布局,并且布局在列中而不是跨页面运行时将是可读的,您可以使用 multicol 作为简单的后备。 不支持 Grid 的浏览器会得到多列显示,支持 Grid 的浏览器会得到 Grid Layout。

不要忘记多列!

我经常回答 Grid 和 Flexbox 问题,答案是不使用 Grid 或 Flexbox,而是使用 Multicol。 您可能不会在每个站点上都使用它,但是当您遇到用例时,它会很有帮助。 在 MDN 上,有很多有用的资源可用于 multicol 和相关的分片属性。

如果您在项目中使用过 multicol,也许可以在评论中添加注释,以分享我们可以使用该功能的其他方式。