对于嵌套 HTML 文本,如果希望每个短语保留自身方向而不影响相邻内容,请选择隔离。仅当有意让短语与周围文本交互时才使用嵌入;只有设计明确要求强制字符顺序时才使用覆盖。
本指南帮助在 Mac 上编辑 HTML 页面的人选择合适的机制、保留嵌套标签和标点,并在桌面浏览器中检查结果。示例使用虚构的标签、数字和几何字符。
哪种机制适合此布局任务?
先问两个问题:浏览器是否应在短语内部应用常规双向文本排序?该短语是否应影响周围文本的排序?这两个决定构成了以下实用对比。MDN 的 unicode-bidi 参考介绍了底层 CSS 行为。
| 要求 | 机制 | 首选 HTML 方法 |
|---|---|---|
| 为方向已知的短语设定独立边界 | 隔离 | 使用现有行内元素,并添加 dir="ltr" 或 dir="rtl" |
| 隔离方向未知的短语 | 自动判定方向的隔离 | 使用 bdi,或为现有行内元素添加 dir="auto" |
| 创建仍会影响周围排序的方向作用域 | 嵌入 | 使用 unicode-bidi: embed 的特殊 CSS 情形 |
| 强制字符顺序,同时隔离结果 | 隔离式覆盖 | 使用 bdo,并明确指定 dir="ltr" 或 dir="rtl" |
| 强制字符顺序,同时保留与周围文本的交互 | 非隔离式覆盖 | 使用 unicode-bidi: bidi-override 的特殊 CSS 情形 |
对于常规 HTML 编写,从方向标记开始。W3C 建议紧密包裹每个反方向短语,并通过嵌套标记表达嵌套短语。这样,预期边界在文档中一目了然。W3C:HTML 中的行内标记和双向文本。
应如何标记嵌套的隔离文本?
为每个完整短语设置独立的方向边界。如果现有行内元素恰好只包含该短语,就在那里添加 dir。否则,添加一个 span。属于该短语的标点应放在其包裹范围内;周围句子的标点则放在外面。W3C 将此称为“紧密包裹”短语。W3C 的行内标记指南。
对于一个设计为从右向左书写、且包含从左向右标识符的合成形状标签,结构可以采用以下示例片段:
<p dir="ltr">
Tile <span dir="rtl">● <span dir="ltr">A1 + B2</span> ■</span>: 12 items.
</p>
这里有三个有意设定的作用域:外层句子、形状序列和嵌套标识符。计数属于句子,因此它留在形状序列之外。若只标记外层短语,内部标识符就没有自己的显式边界。这种嵌套遵循 W3C 对方向变化的推荐结构。W3C 的嵌套短语指南。
如果插入标签的方向未知,bdi 会提供隔离,并默认自动检测方向。未带 dir 的普通 span 不会提供相同的默认行为。WHATWG 规定,bdi 默认使用 auto,而不是像通常情况那样继承方向。HTML 标准:bdi 元素。
自动判定方向是一种启发式方法,根据第一个具有强方向性的字符进行判断,并对嵌套方向元素作出规定的排除处理。它无法理解标签的预期含义。因此,以 A1 开头的标签会提供从左向右的提示,即使其后续内容暗示应采用不同的呈现方式。如果已知要求,请使用显式方向。MDN:dir 全局属性。
只包含形状和数字的标签需要特别留意:其中没有强方向性的字母。对于此处的常规行内示例,如果自动判定方向时找不到符合条件的字符,HTML 算法会回退到从左向右。如果该合成序列必须以从右向左为基准方向,请指定 dir="rtl"。HTML 标准:dir 属性。
何时适合使用嵌入和覆盖?
嵌入会创建另一个方向层级,同时保留其中的常规字符排序。它的边界也会对周围文本产生方向影响。隔离则为内容提供独立作用域,同时使该序列对周围内容保持中性。W3C 的规范明确区分了这些内部和外部影响。CSS Writing Modes Level 3:嵌入和覆盖。
只有当这种外部方向影响属于预期结果时才选择嵌入。对于后面跟着独立计数的独立嵌套标签,通常应选择隔离。仅仅因为嵌套更深,并不足以选择 embed:隔离的 span 本身也可以包含更深一层的方向 span。
覆盖会改变内部规则。它会强制紧邻文本按指定方向排列,而不是让常规算法解析其方向文字段。isolate-override 会在这种强制排序周围添加隔离边界。这是两种不同的行为,并非用于修正普通短语的更强设置。MDN:unicode-bidi 值。
对于有意展示字符顺序的示例,请使用 bdo,并搭配 dir="ltr" 或 dir="rtl"。HTML 标准要求显式指定方向,并禁止在此元素上使用 auto。其呈现规则使用 unicode-bidi: isolate-override,因此当前 HTML bdo 行为包含隔离。HTML 标准:bdo 元素、HTML 标准:双向文本呈现。
对于拉丁字母标签,这一区别很重要:从右向左的基准方向不等于“反转每个拉丁字符”。覆盖可以强制字符按此顺序排列。即便如此,字形本身仍保持原有朝向;bdo 不会把字母形状反向绘制。MDN:bdo 元素。
在 Mac 上试用完整的对比页面
以下独立页面只需浏览器和纯文本编辑器即可使用。前两行对比常规方向处理和强制排序。其余行展示嵌套和边界选择。CSS 嵌入行用于演示机制;对于常规的独立标签,请从 HTML 隔离行开始。
在 TextEdit 中,选择 File > New,然后选择 Format > Make Plain Text。粘贴下面的完整代码。选择 File > Save,将文件命名为 bidi-demo.html;如果出现提示,请选择 Use .html。这是 Apple 记录的创建 HTML 文件的步骤。然后在桌面浏览器中打开保存的文件。Apple:在 Mac 上的 TextEdit 中使用 HTML 文稿。
<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bidi boundary comparison</title>
<style>
body {
font-family: system-ui, sans-serif;
max-width: 44rem;
margin: 2rem auto;
padding: 0 1rem;
line-height: 1.7;
}
.sample {
border: 1px solid #777;
padding: 0.75rem;
}
.scope {
background: #eeeeee;
outline: 1px dotted #555;
}
.embedding {
direction: rtl;
unicode-bidi: embed;
}
</style>
</head>
<body>
<h1>Bidi boundary comparison</h1>
<h2>Ordinary right-to-left base</h2>
<p class="sample">Before <span class="scope" dir="rtl">ABC</span> after.</p>
<h2>Forced right-to-left sequence</h2>
<p class="sample">Before <bdo class="scope" dir="rtl">ABC</bdo> after.</p>
<h2>Nested isolation</h2>
<p class="sample">Tile <span class="scope" dir="rtl">● <span dir="ltr">A1 + B2</span> ■</span>: 12 items.</p>
<h2>Embedding comparison</h2>
<p class="sample">Tile <span class="scope embedding">● <span dir="ltr">A1 + B2</span> ■</span>: 12 items.</p>
<h2>Automatic isolated direction</h2>
<p class="sample">Tile <bdi class="scope">A1 (12)</bdi>: 12 items.</p>
</body>
</html>
先检查前两行,不要做任何更改。常规方向 span 应保持 ABC 的从左向右字母顺序。覆盖行在从左边缘读取时应显示 CBA。这是根据已记录机制得出的预期,并非报告的浏览器测量结果。MDN:bdo 行为。
接下来,对比嵌套隔离行和嵌入行。检查形状序列及其边界处的标点时,保持单词和计数不变。即使某个特定示例看起来相同,机制仍然不同:隔离和嵌入并不保证对每个字符串都产生可见差异。它们的文档化区别在于作用域如何参与周围的双向文本解析。W3C:CSS Writing Modes Level 3。
要进行有效的边界测试,请把冒号移到外层方向 span 内,保存并重新加载,然后再将它移回外面。你正在改变哪个短语包含该标点,因此应根据预期的归属来评估结果。最后,缩窄浏览器窗口,检查句子换行时这些边界是否仍然正确。
背景色和虚线轮廓用于标识正在测试的 span,方便检查。它们不会设置方向或隔离。
如果结果看起来仍不对,应如何诊断?
从受影响最小的短语开始,逐步向外检查。一次更改多个方向属性,会让你难以判断是哪条边界导致了结果。
- 检查包裹元素。 它是否包含完整标签,而且只包含该标签?除非句子标点和计数属于标签,否则应将它们放在外面。
- 检查嵌套短语。 另一个短语中的独立定向标识符可能需要自己的
dir包裹元素。 - 检查自动判定方向。 如果已知预期的基准方向,请将
auto替换为该显式方向。这对合成形状和数字尤其有用。 - 检查覆盖。 如果字符顺序意外被强制,请检查
bdo和 CSSunicode-bidi声明。 - 检查 CSS 层叠。 作者样式规则可能会替换浏览器的方向样式。移除试验性的双向文本规则,然后重新测试 HTML 标记。
前两项检查遵循W3C 的包裹和嵌套指南。自动方向检查遵循MDN 的 dir 文档;最后几项检查遵循HTML 呈现规则。
还要区分排序和对齐。text-align: right 会将行内内容放在区块的右边缘,但不会建立隔离短语。text-align: start 会遵循区块的方向,因此基准方向的变化也可能改变它使用的边缘。应分别诊断字符顺序问题和文本行的位置。MDN:text-align。
关于兼容性,WHATWG 记录了 bdi 和 bdo 在所有当前浏览器引擎中均受支持。但这并不代表所有旧版浏览器或嵌入式查看器都支持它们。检查其他渲染环境时,应在实际目标环境中测试,并保留方向 HTML 标记:MDN 建议优先使用此方式,而非仅依赖 CSS 隔离,因为样式可能会被忽略。HTML 标准:文本级语义、MDN:bdi 使用说明。
最后,为每个嵌套短语明确决定其基准方向、边界,以及内部字符顺序是否应保持常规。对于独立标签,从隔离开始。只有当布局需要其特定的文档化行为时,才保留嵌入或覆盖。
来源
- HTML 中的行内标记和双向文本 — W3C。
- CSS Writing Modes Level 3 — W3C。
- HTML 标准,面向 Web 开发者的版本:文本级语义 — WHATWG。
- HTML 标准:呈现 — WHATWG。
- HTML 标准:
dir属性 — WHATWG。 unicode-bidiCSS 属性 — MDN Web Docs。bdi:HTML 双向文本隔离元素 — MDN Web Docs。bdo:HTML 双向文本覆盖元素 — MDN Web Docs。dirHTML 全局属性 — MDN Web Docs。text-alignCSS 属性 — MDN Web Docs。- 在 Mac 上的 TextEdit 中使用 HTML 文稿 — Apple。