使用 text-wrap pretty 提升排版质量

text-wrap: pretty 的支持已在 Safari 技术预览版中发布,为网页排版带来了前所未有的精细度。让我们看看 WebKit 版本 pretty 的功能——它可能比您预期的要多得多。然后,我们将它与 balance 和其他 text-wrap 值进行比较,以便更好地理解何时使用哪个。

关于“良好”排版理念的根基深植于过去使用金属、木材或墨水手工排字的时代。排字工人会非常谨慎地决定一个词应该放在一行的末尾、下一行的开头,还是用连字符拆分。他们的努力改善了理解力,减轻了眼睛疲劳,并使阅读体验更加愉悦。尽管美感是主观的,对于“更好”的定义存在分歧,但全球各地也存在着根深蒂固的排版传统,代表着各种语言和文字。这些传统通过几个世纪将人们的文化代代相传。

在数字排版中,所有文字都是由计算机而非人工排版。通常,作为网页设计师或开发人员,您正在创建用于填充不同版本内容的模板。在网页上,尤其是在布局流动、可根据不同屏幕形状和尺寸重新排版的情况下,无法进行“手动微调”排版。那么,我们现在能做些什么来更好地表达传统排版对质量的期望,同时仍然依赖于当今计算机带来的机械化呢?

一个解决方案是 text-wrap:pretty。它旨在通过利用基于段落的算法来解决长期存在的问题,从而为网页上的文字带来新的精细度。

更好的排版

某些排版传统教导您要做到以下几点

  1. 避免过短的末行。您应避免让段落末尾只剩下一个单词。这看起来会很奇怪,并使段落之间的空间显得错误地过大。
  2. 避免“不良的行尾不齐”。您可以查看文本的参差不齐的边缘(行内末端),并注意行的整体长度是否一致,或者行尾不齐是否非常锯齿状。在手工排版时,排字工人会移动单词以尽量减少相邻行之间的视觉差异——以避免不良的行尾不齐。“良好的行尾不齐”可以提高文本的可读性,并使整个文本块看起来更美观。
  3. 避免糟糕的连字符。对于可以连字符的语言,连字符有助于形成良好的行尾不齐。它还会将一个单词分成几部分,并将这些部分在行内维度上尽可能地分开。这增加了阅读时的认知负担。最好尽量减少连字符的使用,并避免连续两行使用连字符。
  4. 避免排版河流如果您知道要寻找河流,您可能会开始注意到有时单词之间的空格会随机地跨行对齐,从而在段落中形成一条空白路径。河流可能会分散注意力。

您可以在下面的示例中看到这四个问题。左右两侧的文本是相同的。

A screenshot of paragraph text that demonstrates a short last line, bad rag, bad hyphenation, and a typographic river.

设计师和排版师通常会使用连字符和/或对齐来改善行尾不齐,但在网页上,两者都无法提供令人满意的结果。直到最近,在网页上解决短行、糟糕的行尾不齐或河流几乎是不可能的。我们只是习惯了它们。

自1991年以来的网页行布局

30多年来,网页只有一种确定文本换行位置的技术。

浏览器从文本的第一行开始,逐个单词或音节地布局,直到空间不足。一旦没有更多空间容纳另一个单词/音节,它就会换到下一行(如果允许换行)。然后它开始下一行,尽可能地填充所有内容……然后当空间不足时,它就会换行……并开始处理下一行。

它总是每次只考虑一行。它在上一行填充最大内容量后,只要需要就会换行。如果开启了连字符,它会连字符处理行尾的最后一个单词,尽可能地将单词的大部分留在上一行。没有考虑其他任何因素——这就是为什么网页上的文本会出现糟糕的行尾不齐、河流、短末行和毫无意义的连字符。

这并非计算机排版文本的必然结果。几十年来,Adobe InDesign 和 LaTeX 等软件在决定一行在哪里结束、下一行在哪里开始时,都是一次评估多行文本。只是网页没有使用多行算法。直到现在。

我们很高兴首次将此功能带到网页上,这在 Safari 技术预览版 216 中实现。

text-wrap: pretty

现在,网页具备了在确定最佳换行位置时评估整个文本段落的能力。您可以通过使用 text-wrap: pretty 来要求浏览器执行此操作。WebKit 并非第一个实现此功能的浏览器引擎,但我们是第一个使用它来评估和调整整个段落的浏览器。我们也是第一个使用它来改善行尾不齐的浏览器。我们在实现中选择了更全面的方法,因为我们希望您能够使用此 CSS 来使文本更易阅读,对眼睛更友好,为用户提供更好的可读性、可访问性。简而言之,是为了创造美。

Safari 技术预览版 216 可以防止短行,改善行尾不齐,并减少对连字符的需求——无论文本有多长,都适用。我们尚未进行调整以防止河流,尽管我们未来很乐意这样做。

尽管 pretty 的支持已于 2023 年秋季在 Chrome 117、Edge 177 和 Opera 103 中发布,并于 2024 年在 Samsung Internet 24 中发布,但 Chromium 版本的实现功能更为有限。根据 Chrome 团队的一篇文章,Chromium 仅对段落的最后四行进行调整。它专注于防止短末行。如果段落末尾出现连续的连字符行,它还会调整连字符。

pretty 的目的,正如 CSS 工作组所设计的那样,是让每个浏览器尽其所能改进文本换行方式。CSS Text Level 4 规范目前将其定义为(其中“用户代理”指网络浏览器,着重部分已加粗):

用户代理除其他外,可以尝试避免过短的末行……但它也应该以其他方式改进布局。具体的改进集取决于用户代理,可能包括以下内容:减少行长之间的差异;避免排版河流;优先处理不同类别的软换行机会、连字符机会或对齐机会;避免在过多连续行上使用连字符。

这里“可以”这个词的使用非常有意义。它明确指出,每个浏览器都可以自行决定 pretty 应该做什么。没有强制要求每个浏览器都做出相同的选择。事实上,一个浏览器团队可能在 2025 年决定处理改进这些质量的某些方面,然后在未来改变其实现方式。

由于 Chrome 对 pretty 的实现方式被广泛宣传,许多网页开发者认为此值仅用于防止短末行。但这从未是其意图。事实上,CSS 工作组为此目的定义了另一个值。它上周刚刚更名为 text-wrap: avoid-short-last-lines

看一看

您今天就可以在 Safari 技术预览版 216 中尝试 text-wrap: pretty。请查看此演示,您可以在其中切换 pretty 的开/关以查看其效果。您还可以切换连字符或对齐方式以尝试任何组合。显示参考线和显示重影将帮助您了解正在发生的事情。或者尝试 text-wrap: balance 以查看差异。该演示包含英文、阿拉伯文、德文、中文和日文内容,因此您可以在不同的书写系统中看到效果。

Screenshot of the demo showing a control panel of options that include: text-wrap: pretty, hyphenate, justify, show guides, show ghosts, text-wrap: balance. With a bunch of text on the page which will change as different options are applied.
请在 Safari 技术预览版 216 中尝试此演示

这是未应用 text-wrap 的英文文本示例。这是网页多年来一直使用的默认换行算法。我已打开“显示参考线”来标记文本框的边缘。绿线标记了框的行内末端——行布局算法旨在让每行到达的位置。当文本到达这条绿线时,浏览器就会换行。

Three paragraphs of text, with a green vertical line marking the inline end edge of the text box.

这是应用 text-wrap: pretty 后相同文本的显示效果。绿线已移动。现在,浏览器改为旨在让每行在达到文本框最大限制之前换行。它在一定范围内换行,肯定在洋红色线之后,肯定在红色线之前。这改善了行尾不齐。

Demo of the same text, only now with better rag. The "guides" show three vertical lines about 50 pixels apart — the far right edge is marked with a red line. 45 pixels in from the left is a vertical green line. And another 45 pixels left of that line is a vertical magenta line.

您还可以“显示重影”以在背景中查看未美化版本的重影。

The same text, only now the well wrapped version is in normal color text, with the previous, badly wrapped version directly behind the good version, in a faint cyan color. It's a ghost of the before version, making it clear which lines have changed and how.

您还可以切换连字符和对齐方式的开/关,以比较不同的组合。调整浏览器窗口大小,查看在不同文本宽度下的效果。

您可能会注意到,由于 Safari 技术预览版将 pretty 应用于每一行文本,而不仅仅是最后四行,因此它对文本的影响更显著。文本块变得更像一个实心矩形。

您真的需要使用 text-wrap: pretty 来排版正文文本,才能看出它带来了多大的不同。这种差异很微妙,但引人注目。将其与段落边距 1lh 结合使用,文本就会开始看起来非常棒。

那么,为什么不是每个浏览器都尽其所能地让文本看起来更好呢?因为性能。

性能

许多开发者对 text-wrap: pretty 的性能感到担忧是可以理解的。虽然更好的排版在视觉上令人愉悦——但它不能以牺牲页面速度为代价。每个浏览器工程团队在决定如何设置限制时,都必须考虑其用户拥有的硬件和芯片。

我们对所做的工作感到非常高兴,因为我们确保 Safari 用户不会遇到负面性能影响,即使网页开发者在网页上对大量内容应用了 text-wrap: pretty

作为开发者需要知道的一点是,text-wrap 的性能不受页面上应用它的元素数量的影响。性能问题出现在 pretty 算法在计算时考虑的行数越来越多。在基于 WebKit 的浏览器或应用中,您的文本元素需要有数百或数千行长才能看到性能下降——而这种内容在网页上并不常见。如果您的内容被分成典型长度的段落,那么您无需担心。尽情使用 text-wrap: pretty,并相信我们的浏览器工程师将确保您的用户不会遇到任何负面影响。

我们可能会决定添加一种机制,将非常长的段落分解成更合理的分块,WebKit 分别评估每个分块。如果这样做,即使是 1,000 行的段落也不会影响性能。这就是 Adobe InDesign 采取的方法。它改善了所有文本行的布局,但它不会一次性、一遍地评估每个段落中无限数量的行。WebKit 团队可能还会发现其他平衡美观和速度的方法,确保 pretty 尽最大可能改进您的所有文本,而不会影响用户对我们极速浏览器的体验。

今天就在 Safari 技术预览版 216 中试用 text-wrap: pretty,并告诉我们您是否能触发性能影响。请在 bugs.webkit.org 提交问题,以便我们在该功能正式发布到 Safari 之前对其进行完善时考虑您的反馈。

何时使用 pretty vs balance?

显然,text-wrap: pretty 旨在使正文文本排版更美观。但这是它唯一的用例吗?text-wrap: balance 又如何呢?我们何时应该使用 prettybalance

有些人会给您一个过于简单的答案,例如“pretty 用于段落,balance 用于标题”——但这很可能是个糟糕的建议。让我们看看 balancepretty 的对比,以及如何决定在标题、图片说明、引言和其他较短的换行文本中使用哪一个。

text-wrap: balance

基本上,text-wrap: balance 规则告诉浏览器在适当位置换行,使每行的长度与其他行大致相同。我把它想象成将一张纸折叠成两半、三分之一或四分之一。

例如,这是一个使用默认 text-wrap: auto 的标题。您可以看到单词“enough”最终成为第二行的第一个单词,仅仅是因为在“with”之后第一行没有足够的空间容纳它。每行都是单独布局的,不考虑其他行。这导致这个标题的最后一行只剩下单词“itself”。

这是一个应用 text-wrap: balance 的类似标题。最后一行不再只有一个单词。这太棒了!但这还不是全部。最后一行现在与另外两行大致相同长度。第一行被显著缩短,使其长度与其余行的长度“平衡”。所有三行基本上长度相同。

您会注意到,因此,标题的视觉印记/页面上的“墨水”块现在明显窄于其容器中的总体可用空间(此处用青色线条标记)。

A balanced headline, where all three lines are about the same length. All of them are about two-thirds as wide as the box they are in, leaving a lot of white space on the right. The first line is actually the shortest line.

这 对您的设计来说非常棒。您可以将 balance 应用于标题、图片说明、引言以及任何较短的文本类型,它都会产生相同的效果。它会将文本行堆叠起来,使它们的长度大致相同——它们是平衡的。一旦文本换行,它很可能不再填满整个盒子。它将比可用空间更窄。

有时,这并不是一个理想的效果。也许您的标题位于预告图片下方,而设计要求文本与图片宽度相同。您会注意到在此示例中,第一行最终比其余行短。平衡文本可能代价太高。也许您只是想避免短末行。

您可以在此类标题上改用 text-wrap: pretty。这将避免短末行,同时仍在行内方向上填充容器。

A similar headline, with three words on the last line. The first line does stretch all the way across the box, and the second line is a bit shorter so that some of its words can fill in the last line.

您可以在 Safari 技术预览版 126+ 和 Chrome/Edge 130+ 中亲自尝试这些示例,深入了解 text-wrap 对长、中、短标题的影响。拖动盒子的一角,看看它们处理换行的方式有何不同。

text-wrap: balance 的性能考虑是什么?同样,CSS 网络标准将决定应该设置何种限制以确保用户体验不受负面影响的任务留给了浏览器引擎。浏览器不必做出相同的选择。

Chromium 的实现将平衡的行数限制为四行,以确保 Chrome、Edge 和其他基于 Chromium 的浏览器仍然快速。WebKit 的实现不需要限制行数。每一行都将与所有其他行平衡。

那么,如果“pretty 用于正文,balance 用于标题”这个建议过于简单而无法成为好建议,那么更好地思考选择的方式可能是什么?

我是这样想的

  • pretty 可以应用于页面上的任何内容——正文、标题、图片说明、引言等。查看它的效果并判断您是否喜欢。如果您有非常长的段落(或者更确切地说:没有任何段落分隔的长正文文本,例如数百或数千行的文本),请首先测试性能。此外,如果您以动画方式重新换行文本,请测试这是否是个好主意。
  • balance 应该用于您希望所有行长度相同的情况——尤其是标题和图片说明等。并且您不介意整个行组比其容器窄。不要在长篇文本上使用它;那没有意义。
  • auto 是默认值,它目前在计算布局时一次只考虑一行,就像自 1991 年以来网页所做的那样(见下文)。
  • stable 应该用于可编辑文本等(见下文)。

仍然不相信 text-wrap: balance 通常不适用于长篇文本?您可以在此演示中亲自尝试。

The same demo, now with `text-wrap: balance` applied to the paragraphs. Each paragraph is now wildly different widths from the others. This is not useful for anything.

看看每个段落的整体宽度是如何调整的,以便所有文本行的长度大致相同,而完全不考虑它们相对于其容器的整体宽度?这就是平衡的作用。在上面的例子中,这意味着每个段落的宽度都与其他的截然不同。这很奇怪。只有当您想要这种效果时才使用它。否则,您可能希望使用其他选项。

text-wrap 的其他值有什么作用?我们来逐一了解。

text-wrap: avoid-short-last-lines

avoid-short-last-lines 值是 CSS Text Module Level 4 规范中最新的值。它尚未在任何浏览器中实现。它将只专注于避免短末行,而让 pretty 完成更多工作。

text-wrap: auto

text-wrap 的默认值目前执行着自 1991 年以来网页所做的事情,即每行文本都独立布局,不考虑多行。(这通常被称为“首次适应”或“贪婪”算法。)

然而,这种情况未来可能会改变!总有一天,浏览器可能会决定更改默认设置,并将某种多行布局算法应用于网页上的所有现有内容。这将改善所有内容,甚至包括旧网站,以及开发者不知道 text-wrap: pretty 的网站。

text-wrap: stable

如果您尝试过 text-wrap: stable,您可能会想“它什么也没做!这是什么?”基本上,目前 stable 的作用与 auto 相同。它使用原始的首次适应换行算法,即每行都被布局以完全填充该行的内容,并且只在必要时换行。

当内容本身可编辑时,这是一种特别好的换行算法选择。如果您的用户正在输入文本,您不希望单词/音节跳动,随着他们输入而改变换行。为确保您的内容不会因后续行的编辑而移动,或者在任何您需要原始行换行的情况下,请应用 text-wrap: stable

如果您以文本不断重新换行的方式制作动画,这也会是一个不错的选择。它将确保始终使用最快的换行算法——如果计算需要快速连续地重复进行,这一点很重要。

通过明确选择 text-wrap: stable,您可以确保即使浏览器重新定义 auto 的功能,此内容也将继续使用原始算法进行换行。

stable 值已获得良好支持

text-wrap-mode 和 text-wrap-style

text-wrap 属性实际上是两个长属性的简写。text-wrap-style 属性用于选择使用的换行算法,而 text-wrap-mode 则允许您开启或关闭换行。

text-wrap-style: auto | stable | balance | pretty | avoid-short-last-lines
text-wrap-mode: wrap | nowrap 

通过同时拥有 text-wrap-modetext-wrap-style 属性,您可以灵活地独立于内容是否换行来更改换行样式,并让这些选择独立地级联。

这意味着您也可以使用简写形式,通过 text-wrap: nowrap 简单地关闭换行。或者,使用 text-wrap: wrap 重新开启换行。在此演示中测试其工作原理。

支持 text-wrap-modetext-wrap-style 长属性以及 nowrapwrap 值在 2024 年 10 月成为“基线新可用”(即所有主流浏览器均可用),当时 Chromium 在 Chrome/Edge 130 中添加了支持。为了确保对使用旧浏览器的用户提供全面的换行支持,您始终可以提供回退到旧的 white-space: nowrap | normal。(但这样做时,请注意同时检查您的空白折叠行为,因为它受 white-space 影响。)

您怎么看?

今天就在 Safari 技术预览版 216 中试用 text-wrap: pretty。我们很乐意听取您的意见。请在 BlueskyMastodon 上找到我,Jen Simmons,分享您的反馈。如果您发现 bug 或问题,请提交 WebKit bug 报告