使用 `text-wrap pretty` 实现更好的排版效果
Better typography with text-wrap pretty
2025年4月8日 作者:Jen Simmons
目录
- Better typography
- text-wrap: pretty
- text-wrap: balance
- text-wrap: avoid-short-last-lines
- text-wrap: auto
- text-wrap: stable
- text-wrap-mode and text-wrap-style
- What do you think?
text-wrap: pretty
的支持已在 Safari Technology Preview 中发布,为 Web 上的排版带来了前所未有的润色效果。 让我们来看看 WebKit 版本的 pretty
做了什么 —— 它可能比你期望的要多得多。 然后,我们将它与 balance
和其他 text-wrap
值进行比较,以更好地理解何时使用哪个。
关于什么是“好的”排版的想法深深植根于使用金属、木材或墨水手工设置类型的时代。 排版员在决定一个单词是否应该放在一行的末尾、下一行的开头或用连字符分隔时,会非常小心。 他们的努力提高了理解力,减少了眼睛疲劳,并且使阅读体验更加愉快。 虽然美丽可能是主观的,对什么是“更好”存在分歧,但在全球范围内也存在强烈的排版传统,代表着各种语言和文字。 这些传统将人们的文化从一代传递到下一代,穿越几个世纪。
在数字排版中,计算机放置所有的单词,而不是人类。 通常,作为 Web 设计师或开发人员,你正在创建一个模板,以填充不同版本的内容。 在 Web 上没有“手动调整”排版,尤其是在布局是流动的,重新流动以适应不同形状和大小的屏幕时。 那么,我们现在可以做些什么来更好地表达传统排版的质量期望,同时仍然依赖于当今计算机带来的机械化?
一种解决方案是 text-wrap: pretty
。 它旨在通过利用基于段落的算法来解决长期存在的问题,从而为 Web 上的类型带来新的润色水平。
Better typography
某些排版传统教会你做几件事:
- 避免短的最后一行。 你想避免在段落末尾留下单个单词。 这看起来可能很奇怪,并使段落之间的空间看起来错误地很大。
- 避免“bad rag”。 你可以查看文本的参差不齐的边缘(inline-end side),并注意行的总体长度是否有点一致,或者 rag 是否非常锯齿状。 在手工设置时,排版员会移动单词以最小化相邻行之间的视觉差异 —— 以避免 bag rag。 “Good rag” 提高了文本的可读性,并使整个文本块看起来更令人愉悦。
- 避免不良的连字符。 对于可以连字符的语言,连字符有助于创建良好的 rag。 它还将一个单词分成几部分,并将这些部分尽可能远地放置在inline dimension中。 这增加了阅读时的认知负荷。 最好尽量减少连字符的使用,并避免连续两行使用连字符。
- 避免 typographic rivers。 如果你知道要寻找rivers,你可能会开始注意到,有时单词之间的空格在各行之间随机对齐,从而在段落中创建空白路径。 Rivers 可能会分散注意力。
你可以在以下示例中看到这四个问题。 左右两侧的文本相同。
设计师和排版员经常使用连字符和/或对齐来帮助改善rag,但在 Web 上,两者都不能提供令人满意的结果。 直到最近,几乎不可能对 Web 上的短行、不良的rag或rivers做任何事情。 我们只是忍受了它们。
Web line layout since 1991
30 多年来,Web 只有一种技术来确定在哪里换行文本。
浏览器从文本的第一行开始,然后一个接一个地布局每个单词或音节,直到它没有空间为止。 一旦没有更多空间来容纳另一个单词/音节,它就会换到下一行(如果允许 wrapping)。 然后它从下一行开始,尽可能多地适应所有内容……然后当它没有空间时,它会换行……并开始处理下一行。
它始终只考虑一行。 它会在需要时随时换行,在上一行容纳了最大数量的内容之后。 如果启用了连字符,它将用连字符连接该行中的最后一个单词,在任何时候都尽可能多地将该单词保留在上一行。 没有考虑其他任何因素 —— 这就是 Web 上的文本具有不良的 rag、rivers、短的最后一行和毫无意义的连字符的原因。
这并不是因为文本是由计算机布局的而要求的。 几十年来,Adobe InDesign 和 LaTeX 等软件在决定在哪里结束一行并开始下一行时,已经评估了多行文本。 只是 Web 没有使用多行算法。 直到现在。
我们很高兴首次将此功能引入 Web,在 Safari Technology Preview 216 中。
text-wrap: pretty
现在,Web 能够评估整个文本段落,以确定最佳换行位置。 你可以使用 text-wrap: pretty
要求浏览器执行此操作。 WebKit 不是第一个实现它的浏览器引擎,但我们是第一个使用它来评估和调整整个段落的浏览器。 我们也是第一个使用它来改善 rag 的浏览器。 我们选择在我们的实现中采取更全面的方法,因为我们希望你可以使用此 CSS 使你的文本更易于阅读,更柔和,为你的用户提供更好的可读性和可访问性。 并且,只是为了创造一些美丽的东西。
Safari Technology Preview 216 可以防止短行,改善 rag,并减少连字符的需要 —— 跨所有文本,无论它有多长。 我们尚未进行调整以防止rivers,尽管我们将来很乐意这样做。
虽然 support for pretty
在 2023 年秋季的 Chrome 117、Edge 177 和 Opera 103 以及 2024 年的 Samsung Internet 24 中发布,但 Chromium 版本的实现的功能较为有限。 根据 Chrome 团队的 an article,Chromium 只对段落的最后四行进行调整。 它专注于防止短的最后一行。 如果段落末尾出现连续的连字符行,它也会调整连字符。
CSS 工作组设计的 pretty
的目的是,每个浏览器尽其所能 来改善文本的换行方式。CSS Text Level 4 specification 当前定义如下(其中“user agent”表示 Web 浏览器,强调):
user agent 可能会尝试避免过短的最后一行……但它也应该以其他方式改善布局。 改进的确切集合取决于 user agent,并且可能包括 诸如:减少行之间长度的变化; 避免 typographic rivers; 优先考虑不同类别的 soft wrap opportunities, hyphenation opportunities, 或 justification opportunities; 避免在太多连续的行上使用连字符。 “may”的使用在这里非常有意义。 这是一个明确的声明,即每个浏览器都可以自行决定
pretty
应该做什么。 没有要求每个浏览器做出相同的选择。 事实上,一个浏览器团队可能会在 2025 年决定处理改进这些质量的某些方面,然后在将来更改其实现的执行方式。
由于 Chrome 对 pretty
的实现方式已经被教授,因此许多 Web 开发人员认为该值只应防止短的最后一行。 但这从来不是意图。 事实上,CSS 工作组为此目的定义了一个不同的值。 上周 just renamed 为 text-wrap: avoid-short-last-lines
。
Take a look
你今天可以在 Safari Technology Preview 216 中尝试 text-wrap: pretty
。 查看 this demo,你可以在其中打开和关闭 pretty
以查看其效果。 你还可以打开或关闭连字符或对齐方式,以尝试任何组合。 “Show guides” 和 “show ghosts” 将帮助你了解正在发生的事情。 或者尝试 text-wrap: balance
以查看差异。 该演示具有英语、阿拉伯语、德语、中文和日语的内容,因此你可以看到在不同书写系统中的效果。
Try this demo in Safari Technology Preview 216.
这是英语文本的示例,没有应用 text-wrap
。 这是 Web 多年来一直使用的默认换行算法。 我已打开 “show guides” 以标记文本框的边缘。 绿线标记文本框的inline-end边缘 —— 行布局算法旨在使每行到达的位置。 当文本到达此绿线时,浏览器会换行。
这是应用 text-wrap: pretty
后相同文本的外观。 绿线已移动。 现在,浏览器改为旨在比文本框的最大限制更早地换行每行。 它在范围内换行,一定在紫红色线之后,一定在红线之前。 这改善了 rag。
你还可以 “show ghosts” 以查看未经修饰的版本作为背景中的 ghost。
你还可以打开和关闭连字符和对齐方式以比较不同的组合。 调整浏览器窗口的大小,并查看在不同文本宽度下会发生什么。
你可能会注意到,由于 Safari Technology Preview 将 pretty
应用于文本的每一行,而不仅仅是最后四行,因此它对文本的影响更大。 文本块变得更像一个坚实的矩形。
你确实必须使用 text-wrap: pretty
来排版正文文本,才能看到它带来的多大差异。 它是微妙的,但非常显着的。 将此与 with paragraph margins of 1lh
结合使用,文本开始看起来非常棒。
那么,为什么每个浏览器不尽其所能使文本看起来更好? 因为性能。
Performance
许多开发人员理所当然地关心 text-wrap: pretty
的性能。 虽然更好的排版在视觉上令人愉悦 —— 但它不能以较慢的页面为代价。 每个浏览器工程团队都必须考虑其用户拥有的硬件和芯片,才能决定如何设置限制。
我们对我们所做的工作感到非常兴奋,以确保 Safari 用户不会遇到负面的性能影响,即使 Web 开发人员将 text-wrap: pretty
应用于 Web 页面上的大量内容。
作为开发人员,要知道的一件事是,text-wrap
的性能不受页面上应用了多少元素的影响。 当 pretty
算法在计算要执行的操作时考虑越来越多的行时,就会出现性能问题。 在基于 WebKit 的浏览器或应用程序中,你的文本元素需要数百或数千行才能看到性能下降 —— 并且这种类型的内容在 Web 上是不常见的。 如果你的内容被分解为典型长度的段落,那么你没有理由担心。 尽可能多地使用 text-wrap: pretty
,并依靠我们的浏览器工程师来确保你的用户不会遇到任何缺点。
我们可能会决定添加一种机制,将真正长的段落分解为更合理的块,其中 WebKit 单独评估每个块。 如果我们这样做,那么即使是 1,000 行的段落也不会影响性能。 这是 Adobe InDesign 采用的方法。 它可以改善所有文本行的布局,但它不会一次性评估每个段落中的无限行。 WebKit 团队也可能发现其他方法来平衡美观和速度,确保 pretty
尽可能多地改善你的所有文本,而不会影响用户对我们速度极快的浏览器的体验。
立即在 Safari Technology Preview 216 中测试 text-wrap: pretty
,让我们知道你是否可以触发性能影响。 在 bugs.webkit.org 上提交一个问题,以便我们可以在 Safari 本身发布此功能之前考虑此类反馈。
When to use pretty vs balance?
显然,text-wrap: pretty
旨在使正文文本更美观地排版。 但这是它的唯一用例吗? 那么 text-wrap: balance
呢? 我们应该何时使用 pretty
或 balance
?
有些人会给你一个过于简单的答案,例如 “pretty 用于段落,balance 用于标题” —— 但这可能是错误的建议。 让我们看一下 balance
与 pretty
的对比,以及如何决定在标题、标题、预告片和其他类型的较短的换行文本上使用哪个。
text-wrap: balance
基本上,text-wrap: balance
规则告诉浏览器以这样的方式换行,以使每行都与其他的长度大致相同。 我认为这就像将一张纸折叠成两半、三分之一或四分之一。
例如,这是一个默认值为 text-wrap: auto
的标题。 你可以看到单词 “enough” 最终成为第二行的第一个单词,仅仅是因为在 “with” 之后,第一行没有足够的空间容纳它。 每行都是逐一布局的,没有考虑其他行。 这导致此标题最终在最后一行上只有一个单词 “itself”。
这是应用了 text-wrap: balance
的类似标题。 最后一行上不再有单个单词。 太棒了! 但这还不是全部。 最后一行现在的长度与其他两行大致相同。 第一行明显缩短,因此其长度与其他的 “平衡”。 所有三行基本上都具有相同的长度。
你会注意到,因此,标题的视觉印记 / 页面上的 “ink” 块现在明显比其容器中可用的整体空间(此处用青色线标记)窄。
这对你的设计来说可能非常棒。 你可以将 balance
应用于标题、标题、预告片、任何较短的副本类型,它将具有相同的效果。 它将堆叠文本行,使它们都具有大致相同的长度 —— 它们是平衡的。 并且一旦文本被换行,它可能不再填充框。 它将比可用空间窄。
有时,这不是理想的效果。 也许你的标题位于预告片图像下方,并且设计要求文本与图像的宽度相同。 你会注意到,在此示例中,第一行最终比其余的短。 平衡文本可能会付出太高的代价。 也许你只想避免短的最后一行。
你可以在这样的标题上改用 text-wrap: pretty
。 这将避免短的最后一行,同时仍然在inline direction上填充容器。
你可以在 Safari Technology Preview 126+ 和 Chrome/Edge 130+ 中 try out these examples yourself,以更深入地了解 text-wrap
对长、中和短标题的影响。 拖动框的角以查看它们如何以不同的方式处理换行。
text-wrap: balance
的性能注意事项是什么? 同样,CSS Web 标准将其留给浏览器引擎来决定应实施哪种限制,以确保用户体验不会受到负面影响。 浏览器不必做出彼此相同的选择。
Chromium 的实现将平衡的行数限制为四行,以确保 Chrome、Edge 和其他 Chromium 浏览器仍然很快。 WebKit 的实现不需要限制行数。 每行都将与其他所有行平衡。
因此,如果 “pretty 用于正文文本,balance 用于标题” 过于简单,无法成为好的建议,那么思考这种选择的更好方式可能是什么?
我是这样想的:
pretty
可以应用于页面上的任何内容 —— 正文文本、标题、标题、预告片等。 查看它所做的操作,如果你喜欢该效果。 如果你有_非常_长的段落(或者更好地说:没有任何段落将其分隔开的长正文文本,想想数百或数千行的文本),请首先测试性能。 此外,如果你以这样的方式对文本进行动画处理,使其在动画时重新换行,请测试一下这是否是一个好主意。balance
应用于你_想要_所有行都具有相同长度的任何内容 —— 尤其是标题和标题等。 并且你不介意整体行组比其容器窄。 不要将其用于长的文本段落; 这没有意义。auto
是默认值,目前只考虑在计算布局时一次一行,就像 Web 自 1991 年以来所做的那样(请参见下文)。stable
应用于可编辑文本等(请参见下文)。
不相信 text-wrap: balance
通常在长的文本段落上没有意义? 好吧,你可以在 this same demo 中尝试一下。
请参阅如何调整每个段落的整体宽度,以便所有文本行都具有大致相同的长度,而无需考虑它们与容器相比的整体宽度? 这就是平衡所做的事情。 在上面的示例中,这意味着每个段落的宽度与其他段落的宽度都截然不同。 这很奇怪。 仅当你想要该效果时才使用它。 否则,你可能要使用另一个选项。
text-wrap
的其他值是什么? 让我们来浏览一下。
text-wrap: avoid-short-last-lines
avoid-short-last-lines
值是 CSS Text Module Level 4 规范中的最新值。 它尚未在任何浏览器中实现。 它将专注于避免短的最后一行,让 pretty
做更多的事情。
text-wrap: auto
text-wrap
的默认值目前执行 Web 自 1991 年以来所做的事情,其中文本的每一行都是单独布局的,而无需考虑多行。(这通常称为 “first-fit” 或 “greedy” 算法。)
但是,这在将来可能会发生变化! 将来有一天,浏览器可能会决定更改默认设置,并将某种多行行布局算法应用于 Web 上的所有现有内容。 这将改善所有内容,甚至是旧网站,甚至是开发人员不知道 text-wrap: pretty
的网站。
text-wrap: stable
如果你尝试过 text-wrap: stable
,你可能会认为 “它什么也不做! 这是什么?” 基本上,现在,stable
执行与 auto
相同的事情。 它使用原始的 first-fit 换行算法,其中每一行都被布局为完全用内容填充该行,并且仅在必要时换行。
当内容本身可编辑时,这是换行算法的特别好的选择。 如果你的用户正在编写文本,你不希望单词/音节跳来跳去,更改他们在键入时的换行。 为了确保你的内容不会因后续行上的编辑而移动,或者在任何你想要 OG 行换行的情况下,请应用 text-wrap: stable
。
如果你以这样的方式对文本进行动画处理,使其不断重新换行,这也是一个不错的选择。 它将确保始终使用最快的换行算法 —— 如果要快速连续地一遍又一遍地进行计算,这一点很重要。
通过显式选择 text-wrap: stable
,你可以确保即使浏览器重新定义 auto
的功能,此内容也将继续使用原始算法换行。
stable
值已经 well supported。
text-wrap-mode and text-wrap-style
text-wrap
属性实际上是两个 longhands 的简写形式。 text-wrap-style
属性用于选择使用的换行算法,而 text-wrap-mode
允许你打开和关闭换行。
text-wrap-style: auto | stable | balance | pretty | avoid-short-last-lines
text-wrap-mode: wrap | nowrap
通过同时具有 text-wrap-mode
和 text-wrap-style
属性,你可以灵活地独立于内容是否换行来更改换行样式,并让这些选择独立级联。
这意味着你还可以使用简写形式来简单地使用 text-wrap: nowrap
关闭换行。 或者,使用 text-wrap: wrap
重新打开换行。 在 this demo 中测试它的工作方式。
Support for text-wrap-mode
和 text-wrap-style
longhands,以及 nowrap
和 wrap
值,在 2024 年 10 月成为 “Baseline Newly Available”(也就是,在所有主要浏览器中都可用),当时 Chromium 在 Chrome/Edge 130 中添加了支持。为了确保对使用旧浏览器的用户的换行提供完整支持,你始终可以提供对旧版 white-space: nowrap | normal
的回退。(white-space)。(虽然当你这样做时,也要注意检查你的空白折叠行为,因为它会受到 white-space
的影响。)
What do you think?
立即在 Safari Technology Preview 216 中试用 text-wrap: pretty
。 我们很乐意听取你的想法。 在 Bluesky 或 Mastodon 上找到我,Jen Simmons,分享你的反馈。 如果你发现错误或问题,请提交 WebKit bug report。