很多人做网页的时候,都会发现一个很烦人的问题:段落最后的孤行孤零零地甩在那里,像尾巴一样。搞设计的叫这玩意儿孤儿(orphans),就是一段话末尾只剩一个单词或者一个字,看起来特别别扭。还有排版里的河流(rivers),就是单词之间的空格莫名其妙地在垂直方向上串成一条线,读起来眼睛很难受。这些破事儿在网页上存在了几十年,以前根本没法解决,只能忍着。
现在好了,CSS里出了一个新玩意儿叫text-wrap: pretty。简单来说,它是一个能让浏览器自动优化文本换行的属性。传统浏览器换行的逻辑很简单,像个饿死鬼一样拼命往一行里塞单词,塞不下了才换到下一行,根本不考虑整体好不好看。text-wrap: pretty就不一样了,它会往前看、往后看,评估整个段落的布局情况,动态调整换行策略,把那些难看的孤行、参差不齐的锯齿边、滥用连字符的问题都尽量避开[reference:0][reference:1]。
text-wrap: pretty是CSS Text Module Level 4规范里引入的属性,专门针对长段落正文设计的,目的是让网页排版向专业桌面出版软件(像Adobe InDesign那种)看齐[reference:2]。这个值目前已经得到主流浏览器的支持:Safari Technology Preview 216+、Chrome 117+、Edge 117+都完全支持,Firefox 120+也有部分支持[reference:3]。
一个属性两种玩法
光说概念太干巴了,直接上手。加一行CSS就能让段落排版效果肉眼可见地变好。
.article-content {
text-wrap: pretty;
}就这么简单?就这么简单。把这行代码往样式表里一丢,博客正文的换行质量立刻升一个档次——参差不齐的行尾边缘会变得更平滑,段落末尾不会再出现单蹦的单词,连字符的使用也会被压到最低[reference:4]。打个比方,就像把一件皱巴巴的衬衫拿出来熨了一遍,虽然还是那件衬衫,但精神面貌完全不同了。
两大浏览器的掐架现场
事情到这里本来挺美好的,但翻翻资料会发现一个让人有点懵的情况。Jen Simmons在WebKit博客上发文说,WebKit版的text-wrap: pretty跟Chromium版的实现完全是两码事[reference:5]。
Chromium那头的逻辑比较保守:只管段落最后四行。它主要盯着两件事——防止最后一行太短(至少保证两个单词),以及避免段落末尾出现连续两行都以连字符结尾[reference:6]。说白了,Chrome的思路是“够用就行”,用最少的算力把最明显的痛点解决掉。
WebKit这边就猛多了:整个段落从头到尾全部纳入优化范围。不仅是最后几行,每一行的长度、连字符的分布、单词间距形成的空白河流,统统都要算[reference:7]。这相当于请了一个专业的排版师傅来手工调校每一行,精细度完全不是一个级别。
看看下面这张表就清楚了:
| 浏览器引擎 | 优化范围 | 核心策略 |
|---|---|---|
| WebKit(Safari) | 全局段落 | 多目标整体优化 |
| Chromium(Chrome) | 仅末4行 | 启发式规则优先 |
方案一:无脑全上pretty
如果项目对排版质量有要求,最直接的办法就是全局应用。
body {
text-wrap: pretty;
}很多开发者担心这玩意儿会不会把页面拖卡。说实在的,text-wrap的性能瓶颈不在于页面上有多少元素用到了这个属性,而在于pretty算法要处理多少行文本。在WebKit浏览器里,一个文本块得有几百甚至上千行,才会出现肉眼可见的性能损耗——想想看,正常的网页文章哪有段落上千行的?都是拆成一个个中等长度的段落。所以放心大胆地用,不用畏手畏脚[reference:8]。
但有一个坑得提前说:text-wrap: pretty在Chrome里并不是真的全局优化。如果项目中大量使用了Chrome系的浏览器,这个属性在Chrome里的效果跟Safari里的效果差别还挺大的。Chromium只优化最后四行,前面几十行还是老样子。所以如果在Chrome里测试觉得效果不明显,不是代码写错了,是浏览器实现就是这么干的。
方案二:渐进增强加回退
更稳妥的做法是做一层防御。毕竟浏览器兼容性是老大难问题,万一哪天在老版本浏览器里翻车了也不至于崩。
.article-text {
text-wrap: balance;
text-wrap: pretty;
}
@supports not (text-wrap: pretty) {
.article-text {
overflow-wrap: break-word;
}
}这么写的逻辑是:先把text-wrap: balance放上去兜底——balance是专门给标题用的,会让每行字符数尽量均衡。浏览器不支持pretty的话会直接忽略,然后balance生效。如果连balance都不支持,最后的overflow-wrap: break-word保证长单词不会被憋爆[reference:9]。
balance和pretty的适用场景不一样。balance更适合行数少的文本块,比如标题、副标题、引用语,它能把这些短文本的行长拉得差不多平。pretty是给长段正文准备的,牺牲一点性能换更好的排版质量[reference:10]。二者不是替代关系,是互补关系。
不一样的“漂亮”
text-wrap: pretty这个属性的命名其实挺有意思的。“pretty”这个词本身就很主观,什么叫漂亮?什么叫好看?规范的设计者故意没把这个标准定死,而是让每个浏览器自己决定怎么优化、优化到什么程度[reference:11]。
这种开放性设计的结果就是,同样的CSS代码,在不同浏览器里看到的效果可能完全不同。Chrome觉得把最后一行保住了就算pretty,WebKit觉得整段都整整齐齐才叫pretty。有点像两个人对“收拾房间”的理解不一样——一个觉得把地扫了就完事儿,另一个觉得还得擦窗叠被子。
下次调试页面的时候,如果发现Safari和Chrome的段落排版有差异,不用怀疑自己写错了代码。不是代码的问题,是两个浏览器对“漂亮”的理解不一样。
