探索 Web 网页内字符的换行规则

前不久在验收公司项目内一个讨论区相关需求时,看到界面的样式出现这种问题,让从业界面设计两年多的我感到意外和不安…这篇文章将会记录我对 Web 网页内换行规则的理解、实际应用中的解决方案,以及一个突破性新发现。

探索 Web 网页内字符的换行规则

前不久在验收公司项目内一个讨论区相关需求时,看到界面的样式出现这种问题,让从业界面设计两年多的我感到意外和不安。

验收公司项目时发现的问题

是的,讨论区里的一长串数字、一段网址URL、一长串 Emoji 表情超出了容器宽度。讲道理开发应该不会没有设置宽度,因为左图第一段长文本也不会超出容器宽度。

这时我猜测是换行规则没设置好,才导致这种情况的发生。

为了搞清楚文本正常换行显示或溢出容器宽度的具体规则,我便在网上找了一些资料,也做了尝试。这篇文章记录我对 Web 网页内换行规则的理解、实际应用中的解决方案,以及一个突破性新发现。

目录
发现问题
寻找解决方案
新发现:例外的场景
总结
扩展阅读

⊙ 发现问题

网页内影响文字换行规则的 CSS 属性,常用的有两个:word-breakoverflow-wrap 。在讨论换行规则样式的设置之前,我们得先知道如果不主动设置这些换行样式,网页默认的换行的具体规则。

word-break: normaloverflow-wrap: normal时,Chrome 浏览器默认的换行规则是:

  1. 对于 CJK 字符,行内可用宽度不足以显示一个字符时,会另起一行展示。同时会遵循部分避头尾规则。
  2. 对于西文单词[注1],行内可用宽度不足以显示一个单词时,会另起一行展示。当单词宽度大于整个容器宽度时,文本将会超出容器,不强制换行。

注1:上面提到的「西文单词」,实际上指的是一段「连续文本」(网上没找到对应的定义,笔者给起的名字)。「连续文本」指的是一段中间没有换行符的文本。下面列举出我观察到的换行符/非换行符所包含的内容:

1.换行符:指「-」、「?」、「空格」及CJK字符和Emoji。这些字符出现在西文中间且行内可用宽度不足时,浏览器会尝试在换行符号后换行。
2.非换行符:指「/」、「!」、「@」、「.」、「꧂」等西文字符和文字乱码的符号。这些符号出现在一段西文中时,在浏览器也不会主动换行。换个说法是,这些符号与英文单词是一个整体。

所以,在默认情况下,一段比容器宽度还要长的连续文本,是会直接超出容器宽度的,也直接导致了文章开头出现的样式问题。

小知识1:在苹果系统中,按 「Option + 空格键」或「Shift + Option + 空格键」得到的 Unicode 为 空白字符属于非换行符,出现在连续文本时也不会主动触发换行。而直接按键盘「空格键」得到的  空白字符,则属于换行符。
小知识2:因为「-」属于换行符,所以界面设计时遇到显示时间区间的情况,要预留足够宽度或让开发强制换行,如下图:

⊙ 寻找解决方案

上一章节发现了问题的根源,所以接下来要找到解决办法。理想情况下是不影响浏览器其他的默认换行规则,做到「在连续文本到达容器边缘时,强制换行。不超出容器。」。

下面列出两个网页内常用的换行 CSS 属性值所对应的效果,有部分属性是不应该出现在网页内的,设计师们可以看看自己公司项目有没有踩到雷区。

word-break:一段文本换行的规则。


normal:
遵循浏览器默认换行规则,上文有提到
break-all:
官方定义:对于 non-CJK (CJK 指中文/日文/韩文) 文本,可在任意字符间断行。
我的理解:让西文没有了单词的概念,仅在到达容器宽度边缘时才会换行。必定会造成大量断开西文单词。且在部分浏览器下会导致 CJK 字符避头尾处理的效果失效。 //会造成易读性问题,谨慎使用
keep-all:
官方定义:CJK 文本不断行。 Non-CJK 文本表现同 normal
我的理解:所有 CJK 文字和西文,仅在遇到换行符才会触发换行。即汉字的换行规则跟西文默认的换行规则一样,都有单词的概念了。所以也会导致 CJK 字符避头尾处理的效果失效。 //会造成易读性问题,谨慎使用
break-word: 
效果与 overflow-wrap: break-word 一致,MDN文档标明不建议使用(但当前用该属性的网站还挺多)

break-all确实可以断开一段非常长的连续文本,但会一视同仁,强制断开所有单词,尽管下一行有足够的位置让该单词显示。而keep-all则会让中文排版难以阅读。这两种显然不是我们想要的效果。

由此可见,常规情况下我们不需要调整 word-break 的值, 盲目调整反而会造成其他问题。笔者在其他大型网站上就遇到过不少错误设置 word-break: break-all,导致标点符号避头尾处理规则失效和强断单词的情况,看起来特别难受。

不要再随意使用 word-break: break-all 了!

overflow-wrap:当单词无法完整放进行内时的换行规则,用于解决长单词换行问题。


normal:
遵循浏览器默认换行规则,上文有提到
anywhere:
官方定义:为了防止溢出,如果行中没有其他可以接受的断点,则可能会在任何时候破坏本来就不会损坏的字符串(如长字或URL)。此时文本的最小宽度是一个字符。
我的理解:一段比容器宽度还要长的连续文本,在到达容器边缘时会强制换行。
break-word:
官方定义:与 anywhere 值的效果相同,区别是文本的最小宽度是一个单词。

可以看到,anywherebreak-word的换行效果是一样的,都能达到理想的效果,所以我们只要调整 overflow-wrap 属性的其中一个值,即可解决长连续文本超出容器宽度的问题。

至于是使用anywhere 还是break-word,张鑫旭大神提供了方案,如果是 flex 布局则使用anywhere,常规布局则使用break-word


对于文章第一张图右图的 Emoji 显示异常问题,笔者在多个设备上对比后,发现部分设备无法显示这些 Emoji 表情。

查询后发现 Unicode 对不上,乱码中「🙏」表情是 而正常的「🙏」表情则是�&#56911,属于另一个课题,与本文主题无关。

⊙ 新发现:例外的场景

发现了啥

在理清楚网页文字的换行规则后,我在思考一个点:

目前的常见的做法是当行尾有一段比较长的连续文本时,为了保证良好的易读性,该长文本需要另起一行,在行首开始展示,这时上一行的行尾就会缺了一块。为了保障单个单词的易读性,这也是目前最常用的做法。同时也会让文章的右边出现间距不等的空白,视觉上会让人感觉不整齐。

在什么场景下, 才能充分利用这些空间呢
有没有一种场景,可以名正言顺地直接从单词中间断开,甚至让标点符号出现在句首?

答案是:有!如果说我们是为了让文本有良好的易读性,我们才做出「尽量不在单词中间断开」以及「标点符号避头尾」的行为,那么如果一段文本是不需要保证良好的易读性(甚至说一段文本不是给人阅读的),就能打破这个限制。

什么文本不需要给人阅读?我想到了「网址/URL」。
注:网址/URL不完全等于超链接,超链接是指从某个载体指向另一个目标的链接关系。有三种表现形式:
1.网址/URL超链接:是一个站点、网页的完整路径,例如我的个人网站 https://lrd.im
2.超链接:即用图片、按钮、特定文本等来指向某目标,如「点击跳转>」、「立即报名>」
3.锚点/书签:在同一网页内,通常用来返回顶部或定位到某章节的元素。

想想看,我们在下软件、素材的时候,网站上贴出来的网盘网址,都是直接点击跳转,没有细看网址上具体的英文、数字。由此我产生了一个比较激进的定义:

网址/URL 是用来产生交互的,例如:点击、长按、复制、运行等。不需要理解其文本内容的。

所以我认为网页中的网址/URL(通常是<a>标签),可以大胆利用word-break: break-all的特性,让网址不主动换行。最大限度地保证用户产生的文本能填满一行的宽度,文章右边完美对齐。

如果按这个思路,我们甚至可以再进一步,使用line-break: anywhere 同时无视掉 CJK 文本的标点符号避头尾规则…

使用 line-break: anywhere 更极致地处理网址超链接

所以这种或许会适合用在社区贴文、聊天界面等用户生产内容、内容不受限制,且产生超链接前没有富文本编辑功能的场景。以及弹幕发言气泡这种需要极致压缩空间的场景。

谁在这样做?

有这种做法的产品还真不多,我目前只发现一个:微信 iOS 版

微信 App 对长文本的处理

微信聊天时里如果识别到是超链接话题被引用,文本就会变成蓝色可点击状态。且文本换行规则会变为我上面所写的那样,无视任何规则,仅在容器边缘处换行。

而安卓版、电脑版及企业微信,则没有作特殊处理。

当然,我不认识微信内的设计师,所以不知道微信设计团队对网址做这种处理的出发点,有可能是其他原因,也说不定是个 BUG~

实际应用

基于对上述网页内文字换行规则的认知,我也在公司近期的一个需求内实践了一次。针对超链接做强制换行处理。从截图来看,应该是处理过后的效果会好些。

在公司项目里的实际应用

⊙ 总结

这篇文章内容可能比以往要长,名词也比较多,很多地方也是我这几天研究到才发现。总结起来就是这四点:

  1. 清楚知道 Chrome 浏览器的默认换行规则及换行符有哪些;
  2. 在清楚知调整 word-break 值带来的正负面效果之前,不要轻易调整;
  3. 使用overflow-wrapanywhere / break-word 可以解决长连续文本超出容器宽度的问题;
  4. UI 验收时记得测试超长连续文本的效果,避免有无意外情况发生;
  5. 对于可点击跳转的网址,可以用word-break: break-allline-break: anywhere 来进行更极致地排版。

碎碎念:

实际上在这次需求验收中发现的问题,调整换行规则只是其中一种解决方式。前端工程师们还有很多方法可以解决长连续文本超出容器宽度的问题。

但我作为设计师倒是利用了这次偶然的样式问题,了解一遍网页的各种换行规则、增加了一个 UI 验收时必查的一个点,以及一些意外的新发现,收获确实不少~

⊙ 扩展阅读