若要讓以 <br> 標籤分隔的項目在換行時採用凸排,請在其區塊容器上套用 text-indent: 2em hanging each-line。請確認瀏覽器支援這兩個關鍵字;若需兼顧較舊的瀏覽器,請將每個項目設為獨立區塊,並使用內距搭配負縮排。

本指南適用於在 Mac 上編輯小型 HTML 頁面,並希望每個項目都從左側邊緣開始,而續行則向內縮排的使用者。範例使用合成文字,只需要純文字或程式碼編輯器以及瀏覽器。

為什麼一般凸排在換行標籤後會失效

有兩種不同的換行情況需要考量。<br> 會建立明確的換行。軟換行則是在瀏覽器將文字排入可用寬度時發生。你想要的版面會將前者視為另一個項目的開頭,後者視為續行。WHATWG 將 <br> 定義為換行;它不會建立新的段落或項目容器。HTML 標準:br 元素。

單純的負 text-indent 會影響區塊的第一個排版行。因此,加入內距可以為該區塊建立凸排,但不會在每個 <br> 後重新套用外凸。後續項目仍屬於同一個區塊。MDN:text-indent。

CSS 規格定義了此處所需的組合:each-line 包含第一行以及緊接強制換行後的各行;hanging 則會反轉此選取方式。兩者搭配後,會讓軟換行的續行縮排,同時讓每個明確開始的行都保持齊左。W3C:首行縮排。

目標效果如下。以下行尾僅供示意;瀏覽器會根據可用寬度和字型度量決定實際換行位置。

項目 A 從最外側開始,並在文字延伸時繼續
    向內縮排,直到可用寬度不足為止。
項目 B 也從最外側開始,並有自己的
    縮排續行。
項目 C 很短。

修改頁面前先選擇方法

根據現有標記和瀏覽器需求選擇做法。此決策表根據已記載的縮排行為和瀏覽器支援資料整理而成;它是實作輔助資訊,不是獨立的瀏覽器功能。

你的情況 建議做法
明確換行是同一段文字的一部分,而且支援的瀏覽器已足夠 保留換行並使用 hanging each-line
各項目是不同段落或清單項目 為每個項目提供適當的結構標記
較舊的瀏覽器也必須顯示凸排 每個項目使用一個區塊,並搭配內距和負縮排
你只能編輯 CSS,而較舊的瀏覽器不支援這些關鍵字 保持易讀且齊左的版面,或提出修改標記的需求

不要因為基本的 text-indent 受到支援,就推斷這些關鍵字也受支援。MDN 目前的相容性資料列出 Safari 15、Firefox 121 和 Chrome 146 起支援 hanging 和 each-line。較舊的版本可能支援一般縮排,卻不接受這種組合。MDN 瀏覽器相容性資料:text-indent。

也請檢查這些換行是否符合正確的結構。WHATWG 規定 <br> 僅用於內容本身需要換行的情況,且不得用來分隔段落中的主題群組。不同段落應使用段落元素;項目集合則應使用清單標記。HTML 標準:br 元素、HTML 標準:分組內容。

使用原生 CSS 解法並保留換行標籤

以下完整的 HTML 文件示範保留換行的做法。在 Mac 上,將它貼到純文字或程式碼編輯器,存成 hanging-indent.html,然後用瀏覽器開啟該檔案。請使用 HTML 檔案,而不是富文字文件。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Break-separated hanging indent</title>
  <style>
    body {
      margin: 2rem;
      font-family: system-ui, sans-serif;
      line-height: 1.6;
    }

    .entries {
      max-inline-size: 30rem;
      margin: 0;
      white-space: normal;
      text-align: start;
      text-indent: 0;
    }

    @supports (text-indent: 2em hanging each-line) {
      .entries {
        text-indent: 2em hanging each-line;
      }
    }
  </style>
</head>
<body>
  <h1>Sample entries</h1>
  <p class="entries">Entry A: A long sample line describing a pale rectangular panel, a narrow heading area, and a small square beside the heading.<br>
Entry B: Another long sample line describing a circular tile, an open space beneath it, and a row of neutral labels.<br>
Entry C: A short sample line.</p>
</body>
</html>

@supports 條件會先檢查完整宣告,再套用它。不支援此組合的瀏覽器會保留明確設定的齊左版面。功能查詢會依瀏覽器支援情況條件式套用 CSS。MDN:@supports。

將縮排套用在包含文字的區塊 .entries 上。相關屬性適用於區塊容器;將宣告放在 <br> 上,無法為後續項目提供容器。MDN:text-indent。

2em 是可調整的設計選擇。檢查較窄版面後,再試試較小或較大的值。它會建立一致的續行縮排距離;它不會測量「項目 A:」的寬度,也不會自動讓文字對齊在長度不一標籤後的第一個字下方。

若所有瀏覽器都需要凸排,請使用獨立區塊

如果每個項目都是獨立段落,請修改標記,讓每個項目都有自己的首行。以下完整替代方案移除分隔換行,並分別對每個段落套用傳統的凸排計算。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Paragraph hanging indents</title>
  <style>
    body {
      margin: 2rem;
      font-family: system-ui, sans-serif;
      line-height: 1.6;
    }

    .entries {
      max-inline-size: 30rem;
      text-indent: 0;
    }

    .entry {
      margin: 0;
      padding-inline-start: 2em;
      text-indent: -2em;
      white-space: normal;
      text-align: start;
    }
  </style>
</head>
<body>
  <h1>Sample entries</h1>
  <div class="entries">
    <p class="entry">Entry A: A long sample paragraph describing a pale rectangular panel, a narrow heading area, and a small square beside the heading.</p>
    <p class="entry">Entry B: Another long sample paragraph describing a circular tile, an open space beneath it, and a row of neutral labels.</p>
    <p class="entry">Entry C: A short sample paragraph.</p>
  </div>
</body>
</html>

內距會將段落的內容起始位置向內移 2em。負縮排則會將第一行往回移相同距離。換行後的各行仍會從內距設定的位置開始。兩個值必須相同:只改其中一個值,就會改變第一行的起始位置。MDN 記載了負縮排,而 padding-inline-start 則會在邏輯起始邊緣設定內距。MDN:text-indent、MDN:padding-inline-start。

以字級 16 像素為例,2em 的縮排距離是 32 像素:續行向內縮排 32 像素,首行則調整 −32 像素。這是範例中的計算,不是實際測得的顯示結果。

採用此結構時,請移除舊的分隔符。將每個項目的完整內容及其既有的行內格式保留在新的段落中。如果內容是清單,請改用清單項目;此段落範例僅適用於獨立段落。HTML 標準:分組內容。

完成前檢查換行和文字流向

請在兩個較長項目都會換行的寬度下測試頁面。接著加寬視窗,直到它們能排在單行內。使用以下檢查項目,判斷問題出在縮排、換行還是結構。

  1. 檢查每個項目的起始位置。 在保留換行的範例中,每個 <br> 後的文字都應回到最外側。如果沒有,請檢查完整關鍵字組合是否受支援。
  2. 檢查每個續行。 較長的項目應向內縮排。較短的項目應保持齊左,不要多出前置空白。
  3. 檢查預期使用的最窄欄寬。 如果縮排占用太多可用行寬,請縮小縮排距離。
  4. 檢查實際內容。 將內容移至獨立區塊時,請保留每個項目的文字、行內強調格式,以及預期的明確換行。

如果完全沒有換行,請檢查 white-space。範例使用 normal,此設定會合併原始碼空白字元,並允許換行。pre 會保留空白字元,但禁止一般軟換行;pre-wrap 則會保留空白字元,同時允許換行。若續行根本沒有形成,縮排便無法顯現。MDN:white-space。

避免用空格模擬縮排。在 white-space: normal 下,連續空格會合併。也請避免在目前視窗的換行位置加入額外的換行標籤:這會將瀏覽器選擇的續行變成明確起始行,改變 each-line 對它們的處理方式。MDN:white-space、W3C:首行縮排。

讓瀏覽器負責換行和字形塑形。不要將項目拆成字元包裝元素來計算其可見行。W3C 記載了行內邊界會中斷塑形的情況,包括字元之間有非零行內內距、框線或外距。對於此任務,在預期的邊界換行完整項目,可避免在字詞內引入這些額外邊界。W3C:跨元素邊界的塑形。

最後採用符合內容結構的做法:使用 hanging each-line 保留有意義的明確換行,或為獨立項目各自建立區塊。請確認每個項目都從左側邊緣開始,且只有自然換行的續行會在預期使用的寬度下向內縮排。

來源