长文阅读体验一直是资讯站和博客类网站的核心竞争力。当正文容器被拉到1200像素甚至更宽时,单行文字动辄六七十个字,读者的视线从行尾跳回下一行行首时极易串行。传统解决方案是把正文容器限宽后居中,但两侧留下大片空白,浪费了屏幕空间。CSS多列布局提供了第三种选择:借鉴报纸杂志的排版方式,让文本自动流入多个栏位中,既控制了单行字数,又充分利用了横向空间。本文将系统讲解这套布局方案的用法。

多列布局的核心属性与基本用法
CSS多列布局的规范定义了一组以column-为前缀的属性,其中最基础的两个是column-width和column-count。前者指定每一栏的理想宽度,后者指定栏的数量。这两个属性可以单独使用,也可以通过简写属性columns一并声明。先看一个最简单的例子:
.article {
column-width: 300px; /* 每栏理想宽度300px */
column-gap: 40px; /* 栏间距40px */
}
.article-count {
column-count: 3; /* 固定分成3栏 */
}
.article-shorthand {
columns: 300px 3; /* 简写:栏宽300px,最多3栏 */
}这两个属性的配合规则值得仔细理解,也是初学者最容易困惑的地方。当同时设置时,浏览器会遵循一条简单的逻辑:column-width是理想值,column-count是上限。浏览器先根据容器可用宽度除以理想栏宽计算出能容纳多少栏,再与column-count比较,取较小者。比如容器宽1000px、栏宽280px、间距32px,理论上能放3栏(3栏需要 280×3 + 32×2 = 904px,放4栏则需要 280×4 + 32×3 = 1216px,放不下),所以最终渲染3栏。
这种机制带来一个很实用的效果:只写column-width不写column-count时,布局天然具备响应式能力。窄屏下自动退化为1栏,宽屏下自动增加栏数,不需要借助媒体查询。反过来,只写column-count: 3则无论容器多宽都固定3栏,适合需要严格对称版面的场景。根据实际需求选择侧重宽度还是侧重数量,是多列布局的第一课。
除了栏的数量和宽度,column-gap负责控制栏与栏之间的留白,默认值是1em,一般建议根据正文字号设置为1.5em到2.5em之间,太窄会让两栏文字视觉上粘连,太宽则破坏整体的阅读连贯性。column-rule则可以在栏间画一条分隔线,写法和border几乎一致:
.article {
columns: 320px 2;
column-gap: 48px;
column-rule: 1px solid #e0e0e0; /* 细分隔线,杂志常用 */
}需要注意的是,column-gap同时承担了分隔线两侧的留白,分隔线永远绘制在间隙的正中间。如果想做双线效果或者想让分隔线只占部分高度,多列布局本身做不到,需要借助伪元素等其他手段。
控制内容流向:跨栏与截断
多列布局中内容是自动从左栏流向右栏的,但排版中经常需要打破这种自动流。最典型的需求是文章标题横跨所有栏。这就要用到column-span属性,它有两个值:none是默认值,all表示让该元素横跨全部栏位。
.article-title {
column-span: all; /* 标题横跨所有栏 */
text-align: center;
margin-bottom: 1.5em;
}这个特性在制作杂志风格页面时非常关键。常见的结构是把大标题和导语放在顶部横跨全宽,正文从下方开始分栏,中途如果插入小节标题也可以再次跨栏,把文章切分成几个视觉块。要提醒的是,column-span: all会把内容流截成上下两段,浏览器在处理时会强制平衡上方各栏的高度,如果某段内容很短就可能出现大量空白,排版时要预留足够的正文量。
另一个重要属性是break-inside。默认情况下,浏览器会毫不犹豫地把内容切到下一栏,一张图片可能上半截在左栏底部、下半截在右栏顶部,观感很差。给图片、引用块、小卡片加上break-inside: avoid,浏览器就会尽量把它们完整地保持在同一栏内:
.article figure,
.article blockquote {
break-inside: avoid; /* 避免被切到两栏 */
margin: 1em 0;
}
.article p {
orphans: 3; /* 栏底至少留3行 */
widows: 3; /* 栏顶至少留3行 */
}代码中还出现了orphans和widows,这两个属性继承自印刷排版概念:前者控制栏底部最少保留的行数,后者控制栏顶部最少保留的行数。把两者都设为2或3,可以避免段落只剩一行孤零零地悬在栏底或栏顶。此外还有break-before: column和break-after: column,可以强制某个元素从新的一栏开始,适合用来做分栏的小节起点。
实战案例:图文混排的杂志式长文页
下面通过一个完整的例子把前面的知识点串起来。目标是做一个两栏杂志式排版:顶部大标题跨栏,正文双栏,图片不被切断,窄屏自动变单栏。
<article class="magazine">
<h1 class="title">城市漫步指南</h1>
<p class="lead">导语部分,简短介绍文章主旨,吸引读者继续往下看。</p>
<figure>
<img src="https://ipipp.com/images/city.jpg" alt="城市街景">
<figcaption>图1:老城区的清晨</figcaption>
</figure>
<p>正文第一段,内容较长时会自动流入左栏再进入右栏。</p>
<blockquote>好的排版让读者忘记排版的存在。</blockquote>
<p>后续正文段落……</p>
</article>
.magazine {
max-width: 960px;
margin: 0 auto;
column-width: 320px;
column-count: 2;
column-gap: 48px;
column-rule: 1px solid #ddd;
text-align: justify;
hyphens: auto;
}
.magazine .title,
.magazine .lead {
column-span: all;
}
.magazine .lead {
font-size: 1.15em;
color: #666;
border-bottom: 1px solid #ddd;
padding-bottom: 1em;
margin-bottom: 1.5em;
}
.magazine figure {
break-inside: avoid;
margin: 0 0 1.2em;
}
.magazine figcaption {
font-size: .85em;
color: #999;
text-align: center;
}这段代码里有几个细节值得展开。首先是text-align: justify配合hyphens: auto,两端对齐能让两栏的边缘整齐划一,而自动连字符(目前主流浏览器在设置lang="zh-CN"后对英文单词生效)避免了justify在中文里常见的字间距被拉扯过大的问题。其次是column-width: 320px与column-count: 2的组合,在960px宽的容器里刚好渲染成两栏,当视口变窄、容器不足两栏所需宽度时自动合并为单栏,实现无断点的平滑降级。
最后谈谈使用边界。多列布局非常适合纯文本为主的长文场景,但它不适合用来做页面整体框架布局——需要精确定位子元素位置时,Flex布局或Grid布局才是正确工具。多列布局的本质是内容驱动:浏览器决定内容如何流入各栏,开发者只能控制栏的形态和内容的截断行为,无法指定某个段落必须在第几栏。另外要留意固定高度容器下的行为差异:当多列容器设置了height,内容超出时会产生横向滚动或根据column-fill属性决定先填满一栏还是均衡分配。默认值balance会让各栏高度尽量相等,适合普通文章;设为auto则按顺序填满第一栏再流向下一栏,配合固定高度可以实现类似报纸翻页的效果。理解这些边界条件,才能把多列布局用在最合适的地方,做出真正接近印刷品质的网页长文排版。