换行
将文本折行到下一行的处理。在 CSS 中通过 word-break 和 overflow-wrap 属性控制。
换行是将文本从当前行折到下一行的处理。在 Web 开发中,换行分为两种:使用 HTML <br> 标签的显式换行,以及浏览器根据行宽自动进行的折行 (软换行)。通过组合 CSS 的 word-break、overflow-wrap、white-space 属性,可以精细控制自动换行行为。
日语文本由于词与词之间没有空格,原则上几乎可以在任意字符位置换行。而英文文本的基本规则是不在单词中间换行。CSS 中指定 word-break: break-all 后英文也会在任意位置换行,但可读性会下降,需要注意。overflow-wrap: break-word 提供了更温和的控制,只对溢出容器的长单词才在中途换行。overflow-wrap 还有另一个值 anywhere,在单词中途换行这一外观上的行为与 break-word 相同,区别在于是否把这个换行机会计入 min-content (最小内容宽度) 的计算。anywhere 会计入,因此元素的最小宽度可以缩到 1 个字符;break-word 不计入,因此最长单词的宽度会作为下限留下来。当长 URL 在网格或弹性布局中把布局撑开时,这个差别就会左右结果。
禁则处理是日语排版中重要的换行规则。有不让句读点 (。、) 和右括号 (」)) 出现在行首的 "行首禁则",以及不让左括号 (「() 出现在行尾的 "行尾禁则"。用 CSS 的 line-break 属性可以控制禁则的严格程度,可指定的值有 auto、loose、normal、strict、anywhere 共 5 个。表示严格程度阶段的是前 4 个,loose 设想报纸那样行宽狭窄的排版,把禁则放到最宽松,而 strict 下小字假名 (っ、ゃ) 也会成为行首禁则的对象。剩下的 anywhere 不是阶段,而是另设一档的值,它会在句读点的前后、连续空白之中、甚至单词的中途等一切字符的边界上制造换行机会,完全无视禁则。由于连字符也不会被插入,可以把它看作只在无论如何都要塞进狭窄框内的表格或代码显示中才使用的值。
在编程中,换行符的差异经常在实际工作中引发问题。Unix/Linux 使用 LF (0x0A),旧版 Mac OS 使用 CR (0x0D),Windows 使用 CRLF (0x0D0A)。Git 中出现意外的大量差异、CSV 解析器无法正常工作等问题,往往是换行符不一致造成的。使用 .editorconfig 或 Git 的 core.autocrlf 设置来统一换行符是实务中的常见做法。
一个常见的误解是将 HTML 换行与换行符混淆。在 HTML 中,源代码中的换行被视为空白字符,不会产生视觉上的换行。要实现视觉换行,需要使用 <br> 标签,或在 CSS 中设置 white-space: pre-line 来保留换行符的效果。
在字符计数方面,换行符虽然是看不见的控制字符,但会被计入字符数。LF 算 1 个字符,CRLF 算 2 个字符,因此即使内容相同的文本,也会因换行符的种类不同而字符数不同。不过这是以码元或码位为 1 个单位来数时的情况。Unicode 的书写素分割规则规定不切分 CR 与 LF 的排列,因此在以书写素簇为单位计数的计数器中,CRLF 会变成 1 个。把 "a" + CRLF + "b" 实际数一遍,结果是码元 4、码位也是 4、书写素簇 3。当含有换行的文本在多个工具上给出不同的值时,请先怀疑它是以哪个单位在数的。
输入栏一侧也有陷阱。textarea 的 maxlength 与 minlength 是按 UTF-16 的码元单位判定的,因此用代理对表示的表情符号 1 个就要消耗 2。而且随表单发送的值中的换行,无论 wrap 属性取什么值,都会按发送时的序列化规则全部统一成 CR+LF 的成对形式 (默认值 soft 下也一样)。即使在手边是以 LF 输入的,发送时 1 个换行也会变成 2 个码元,所以在行数多的文章里,画面上显示的字符数与服务器端校验的字符数会出现偏差。给含换行的输入设置上限时,请先决定好以哪个单位、数哪个时点的值,然后再着手实现。