對於巢狀 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">&#x25CF; <span dir="ltr">A1 + B2</span> &#x25A0;</span>: 12 items.</p>

  <h2>Embedding comparison</h2>
  <p class="sample">Tile <span class="scope embedding">&#x25CF; <span dir="ltr">A1 + B2</span> &#x25A0;</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,作為檢查輔助。它們不會設定方向或隔離。

如何診斷看起來仍然不對的結果?

從受影響最小的片語開始往外檢查。一次變更多個方向屬性,會讓你難以找出是哪個邊界造成結果。

  1. 檢查包覆元素。 它是否包含完整標籤,而且只包含該標籤?除非句子標點符號和計數屬於標籤,否則應留在外面。
  2. 檢查巢狀片語。 另一個片語中的獨立方向識別碼,可能需要自己的 dir 包覆元素。
  3. 檢查自動判斷方向。 若已知預期的基準方向,請將 auto 替換為明確方向。這對合成形狀和數字特別有用。
  4. 檢查覆寫。 若字元順序意外地被強制,請檢查 bdo 和 CSS unicode-bidi 宣告。
  5. 檢查 CSS 串接。 作者規則可能會取代瀏覽器的方向樣式。移除實驗用的雙向文字規則,然後重新測試 HTML 標記。

前兩項檢查遵循W3C 的包覆與巢狀結構指南。自動判斷方向的檢查遵循MDN 的 dir 說明文件;最後幾項則遵循HTML 呈現規則。

另外也要區分排序和對齊。text-align: right 會將行內內容置於區塊的右緣,但不會建立隔離片語。text-align: start 會依區塊方向決定位置,因此基準方向變更時,所使用的邊緣也可能改變。請分開診斷字元順序問題和文字行的位置。MDN:text-align。

在相容性方面,WHATWG 文件指出 bdi 和 bdo 均受目前所有瀏覽器引擎支援。這不代表所有舊版瀏覽器或嵌入式檢視器都支援。檢查其他呈現環境時,請測試實際目標,並保留方向性 HTML 標記:MDN 建議使用此方法,而非只用 CSS 隔離,因為樣式可能會遭忽略。HTML 標準:文字層級語意,MDN:bdi 使用說明。

最後,為每個巢狀片語明確決定其基準方向、邊界,以及內部字元順序是否應維持一般方式。若是獨立標籤,請從隔離開始。只有在版面需要其特定文件所述行為時,才保留嵌入或覆寫。

來源