改善纽约时报的绕线平衡器

我研究了一些选项,以改进web上换行的断点。我发现了一些“文本平衡器”使用不同方法在尽可能少的行数上平衡每行的字数的程序。我对其中任何一个都不满意,但最终在《纽约时报》的文本平衡器上得到了改进。这不是我想象中的周末。

Web浏览器遵循一个简单的yabo亚博体育下载算法来布局文本:一个词接一个词,当当前行上没有空间时,就换行。它速度快,在大多数情况下都能产生足够好的结果。但是,它不能保证词的均匀分布,你可以自己在一行上找到一个词(称为“寡妇”)。

词的不均匀分布会使设计的一面更重;使其不平衡。它可能是一个大段文字结尾的小问题。但是,当它出现在标题和其他大字体中时,会引起不必要的注意。

最简单的解决方案是重写文本,直到获得更好的匹配。但是,你不能依靠重写文本来为每个访问者获得完美的匹配。匹配程度将取决于屏幕大小和屏幕大小字体和平台(或需要webfont)。为了设计的缘故,你也会做更多的工作,甚至可能会有尴尬的措辞。

文本包装平衡器是一种试图在多行上更均匀地分配单词的程序。至少有24种算法用于实现这一点。在web上最常见的算法是AdobeBalanceText项目。

Adobe文本平衡器分析文本,测量每个单词的长度和文本中断机会(如连字符),并插入换行元素(
)在合适的时间点实现更平衡的换行。它起作用了;但是它速度慢,内存密集,而且过于复杂。

2013年,Adobe提出一种新的CSS文本换行:平衡属性使浏览器完成(并优化)繁重的工作。TextBalancer是此CSS属性的JavaScript实现。该属性尚未在任何web浏览器中实现。(来吧,伙计们!它在CSS文本级别4.)

2017年,时任《纽约时报》实习生的哈里森·利迪亚德(Harrison Liddiard)提出了一种新的更简单的文本平衡器.这个想法产生了纽约时报文本平衡器它比Adobe更复杂的文本平衡器更小、更快、更便宜。

NYTimes文本平衡器测量行数,然后减小文本容器的宽度,直到它在新行上打断为止。然后它稍微加宽容器以避免额外的换行。瞧,一个简单但有效的文本包装器,在标题上非常有效。

该方法适用于标题和单个短文本段落。它不适用于文本的长段落或多个段落。当文本超过几行时,与浏览器的默认布局引擎相比,它不会产生任何好处。最后还会出现宽度不均的段落,这会破坏右侧的内聚性-手绘文字是你设计的边缘。不过,手绘文字适合两到四行文字。

《纽约时报》的文本平衡器并不完美,但它比Adobe的解决方案快得多。两家公司都开放了他们的实现。我查看了《纽约时报》的实施情况,发现有很大的改进空间。本文的其余部分将介绍我对平衡器所做的更改和改进。我必须分享我对它所做的更改,以符合Apache许可证版本2。如果您只对代码感兴趣,那么这是您离开的提示:

获取Codeberg的来源

Codeberg项目页面包含一个boilerplate。html可以用作模板的文件,以及主文件text-balancer.js文件我建议您阅读Codeberg上的使用说明以及本文的其余部分,以了解模板文件中的内容。

NYTimes文本平衡器的第一个问题是,它会在每次调整大小事件时触发。这对性能不好,因为在某些情况下,web浏览器可能会喷出数百个调整大小事件。文本平衡器算法甚至在文本容器的大小没有更改时运行。

NYTimes版本会更改文本元素本身的大小,这也会在将来的计算中用于找到所需的宽度。这意味着它只能收缩文本容器,而不能扩展它。我将实现更改为使用ResizeObserver仅当文本容器的父容器更改大小时才会触发。它假定父容器的维度更改可以用作文本容器及其大小约束的代理。此更改允许它扩展文本容器。

文本平衡器使用二进制搜索算法来确定max-width以应用于文本容器。该算法搜索从0 px到文本容器的全宽度的空间。然而,我们知道答案永远不可能小于文本容器宽度的50%(因为这样它就适合更少的行)。我将文本平衡器的搜索范围改为文本容器宽度的50 - 100%。此更改跳过了二分搜索算法的第一次迭代。

文本平衡器需要确定文本是否分布在多行上。《纽约时报》的多行检查器有缺陷且速度缓慢。它尝试隔离文本的第一个单词,然后根据文本容器的高度测量其高度。但是,该实现将标题中的任何HTML视为纯文本;导致它计算t他输入了错误的行数,而且速度慢,内存不足,并且与文档对象模型(DOM)进行了不必要的交互。

我设法使性能比原来的实现提高了445%getComputedStyle检查文本容器相对于其行高的高度。当标题包含其他内联块元素(例如图像)或样式化的小文本时,我的方法仍然容易出错().然而,如果使用粗体、强调符号、代码、表情符号、子和上标文本、链接以及其他措辞内容格式,效果会更好。

我从互联网档案中的《纽约时报》网站上抽取了几十个页面,在其网站上找不到任何使用《纽约时报》文本平衡器的情况。我可以在2015年和2016年的《纽约时报》网站上找到Adobe文本平衡器的实例。该《纽约时报》网站目前没有使用任何基于JavaScript的文本平衡器。

来自PublicWWW的数据 — 在网站源代码中搜索的服务 — 显示Adobe文本平衡器用于3000个网站。纽约时报文本平衡器目前仅用于德克萨斯论坛报和尼曼实验室。

那么,为什么《纽约时报》和其他网站不使用基于JavaScript的平衡器呢?这可能是因为最后一个遗留问题,这是一个很难解决的问题:未格式化内容的闪现(FOUC)。

FOUC是页面布局之后和加载一些额外资源之前的中间状态。通常,此资源将加载阻止资源,如web字体或样式表。在本例中,我讨论的是初始页面布局呈现和执行文本平衡器脚本之间的中间状态。

在页面布局之前,您无法计算文本平衡并将其应用于文本。但是,您不希望读者看到文本以一种方式布局,然后通过回流文本立即中断阅读。这个问题有些无法解决。这就是为什么Adobe建议web浏览器以本机方式处理此问题的原因使用CSS属性。

最好的方法是在页面内联嵌入所需的JavaScript和CSS,然后在执行文本平衡器之前暂时隐藏文本。这并不理想,但成本也不高。在我的测试中,它会将文本呈现延迟1–9 在快速设备上使用ms,最高可达110 但是,在速度较慢的设备上,在恶劣的网络条件下,渲染会延迟一秒钟以上。

您还需要确保在禁用JavaScript的情况下有一个noscript替代方案。以@媒体(脚本:无)媒体查询。令人难忘的是,它还没有在任何网络浏览器中得到支持,所以我不得不依靠更传统的方法嵌入风格元素在一个乔治·毛内元素。

尽管采取了所有这些预防措施,但仍然存在出错的风险,文本包装器无法正确执行。为了解决这个问题,我添加了一个单独作用域的自调用JavaScript函数,该函数在三秒钟的时间内显示隐藏的文本。

我还想通过检测对CSS的支持并将文本平衡工作推迟到CSS来验证这个实现@支持(文本换行:平衡)CSS查询,与CSS.supports('text-wrap','balance')用JavaScript进行测试。这可能是一厢情愿的想法,但如果未来的浏览器支持它 — 它将绕过文本隐藏并完全包裹平衡舞蹈。

结果并不完美,但它确实是对默认布局引擎的改进。您可以通过在标题中大量使用软连字符(U+00AD)来优化换行结果。软连字符表示浏览器可以将文本换行到新行的可能换行点。它是一个不可见的字符,除非它在行尾时将被呈现为连字符。您可以找到所有编程语言的连字符库,用于动态添加软连字符。(您应该避免CSS断字(连字符:自动),因为它的结果因语言和浏览器而异。)