`word-break: auto-phrase` は貧弱なので `word-break: keep-all` を使うべし

# はじめに

この記事は [2023 年の MDN 翻訳 Advent Calendar](https://qiita.com/advent-calendar/2023/mdn-translation-community-japan) 向けに作成したものです。

こんにちは。debiru です。記事にする MDN ネタがなくて頑張って探しました。我々一生懸命探しました。スタッフ一生懸命探しました。そしてネタ…見つかりました。

今日は、テキストの折り返しに関する CSS プロパティの解説をしていこうかと思います。

# テキストの折り返しに関する CSS プロパティ

- [`word-break`](https://developer.mozilla.org/en-US/docs/Web/CSS/word-break) プロパティ
- [`overflow-wrap`](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap) (旧 `word-wrap`) プロパティ
- [`line-break`](https://developer.mozilla.org/en-US/docs/Web/CSS/line-break) プロパティ
- [`text-wrap`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-wrap) プロパティ

他にも関連しそうなものとして [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space) プロパティや [`hyphens`](https://developer.mozilla.org/en-US/docs/Web/CSS/hyphens) プロパティもありますが、折り返しを制御するものとして上記 4 つのプロパティがあります。

[`text-wrap`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-wrap) プロパティは [CSS Text Module Level 4](https://www.w3.org/TR/css-text-4/#text-wrap) で策定された最新のプロパティで、他のプロパティとは少しやれることが異なるのと、`text-wrap` だけで記事が書けるくらいには情報量がありそうなのでこの記事では扱わないことにします。

というわけで、`word-break`, `overflow-wrap`, `line-break` プロパティを見ていきましょう。

## [`word-break`](https://developer.mozilla.org/en-US/docs/Web/CSS/word-break) プロパティ

非推奨となった値を除くと以下の 3 つの値があります。

- `normal`
    - 通常の単語の分割位置（2 つの単語間の空白など）でのみ折り返す。
- `break-all`
    - ボックスから文字が溢れる場合、単語の途中であっても強制的に文字列を折り返す。
- `keep-all`
    - 単語内では折り返さないようにする。CJK（中国語、台湾語、日本語、韓国語）テキストであってもボックスから文字列が溢れる可能性がある。単語間の空白では折り返しが行われる。また、PC 版 Safari を除くブラウザでは、約物（句読点や括弧）の前後のいずれかでも折り返しが行われる。
- 非推奨：`break-word`
    - この値はもはや非推奨とされているので、知らなくてよい。
    - 効果は、`overflow-wrap` プロパティの値によらず、`word-break: normal; overflow-wrap: anywhere` を指定したのと同等の結果が得られるというもの。

そして、[CSS Text Module Level 4](https://drafts.csswg.org/css-text-4/#word-break-property) では更に `manual` と `auto-phrase` の値が追加されています。

- `manual`
    - テキストを折り返さず、`<wbr>` または Zero Width Space (`&ZeroWidthSpace;`) の挿入位置でのみ折り返すようにする。
- `auto-phrase`
    - CJK テキストを文節（自然なフレーズの境界）で折り返す。ただし、当該要素（またはその先祖要素）に適切な `lang` 属性が付与されている必要がある。
    - 文節の検出には機械学習エンジンが用いられているため、折り返し位置について意図した結果が得られない場合がある。その場合には、`<wbr>` または Zero Width Space (`&ZeroWidthSpace;`) を用いることで折り返し可能な位置を指定することができ、Zero Width Joiner (`&zwj;`) を用いることで折り返しを防止する位置を指定することができる。

Chrome 119 (2023-10-31) では [`auto-phrase` が実装されました](https://developer.chrome.com/blog/css-i18n-features?hl=ja)。この記事では、`auto-phrase` がどのくらい使えるものなのかについて後述します。

## [`overflow-wrap`](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap) (旧 `word-wrap`) プロパティ

次の 3 つの値があります。

- `normal`
    - 通常の単語の分割位置（2 つの単語間の空白など）でのみ折り返す。
- `anywhere`
    - ボックスから文字が溢れる場合、行内に通常の単語の分割位置や `<wbr>` など折り返し可能な位置があればそこで折り返すが、折り返し可能な位置がない場合には単語の途中であっても強制的に文字列を折り返す。また、`width: min-content` を計算するときには折り返し可能位置を考慮した（折り返しを行った）状態での結果が得られる。
- `break-word`
    - `anywhere` と同様だが、`width: min-content` を計算するときに折り返し可能位置が考慮されない。これは `table-cell` や `flex item` などの `shrink-to-fit` であるボックスで文字列が折り返されないことを意味する。

## [`line-break`](https://developer.mozilla.org/en-US/docs/Web/CSS/line-break) プロパティ

次の 5 つの値があります。

- `auto`
    - ブラウザ既定の禁則処理に基づいて折り返しを行う。
    - Firefox では `strict`, Chrome では `normal` 相当の値になっているようである。
- `anywhere`
    - 一切の禁則処理を行わず、全ての文字で折り返す。`word-break` プロパティで折り返さないような値が指定された場合、それを無視する。
- `loose`
    - 最低限の禁則処理に基づいて折り返しを行う。約物（句読点や括弧）の前後のいずれかで折り返す。
- `normal`
    - 一般的な禁則処理に基づいて折り返しを行う。`loose` に加えて「々」などを直前の文字と分離せずに折り返す。
- `strict`
    - 厳格な禁則処理に基づいて折り返しを行う。`normal` に加えて「ゃ、ゅ、ょ」などの小書き文字（捨て仮名）を直前の文字と分離せずに折り返す。

## ブラウザでの動作確認

<p class="codepen" data-height="600" data-default-tab="html,result" data-slug-hash="vYbwGoa" data-user="arcxor" style="height: 600px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/arcxor/pen/vYbwGoa">
  CSS wrap properties</a> by arcxor (<a href="https://codepen.io/arcxor">@arcxor</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### 折り返し位置の調整

以下は Chrome での実行結果です。

![word-break: auto-phrase だと「にゃんちゅう」が1文字目の「に」の直後で折り返している。word-break: keep-all だときれいに「にゃんちゅう」の単語直前で折り返している。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/cd117c07-ec74-b146-829a-5087372f7f0b.png)

(1.) から (5.) は `line-break` の動作確認結果なのでそれほど重要ではありません。
 
(6.) の `word-break: auto-phase` をみると、「にゃんちゅう」の 1 文字目「に」の直後で折り返してしまっています。これは期待する結果ではありません。

(7.) は `<span class="nowbr">「にゃんちゅう」</span>` のようにマークアップして、`.nowbr` に `display: inline-block` を適用しています。ちなみに `nowbr` は `no-word-break` の略です。

(8.) に注目してください。(8.) では `word-break: keep-all; overflow-wrap:anywhere` を指定しています。この画像の例文『日本語がどこで「折り返し」されるのか。あっぱれ「にゃんちゅう」昔々の物語。』では、`<wbr>` 要素タグを記述していません。にもかかわらず `auto-phrase` のように自然なフレーズの境界で折り返しがされています。これは単に単語外の折り返し可能位置で折り返しているだけなので、本当にフレーズの境界で折り返しているわけではないですが、約物（句読点や括弧）が登場する文章ではそれなりに使えるのではないでしょうか。ただし PC 版 Safari は単語間の空白でしか折り返さないようです（iOS Safari は他のブラウザと同様に折り返します）。

#### 窓ぎわのトットちゃん

![「窓ぎわのトットちゃん」という例文の場合。(6.),(7.),(8.) では「トットちゃん」の直前で折り返している。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/e4e0afc8-4f51-409a-5668-b551e713ed9a.png)

「窓ぎわのトットちゃん」の例です。(8.) では `窓ぎわの<wbr>トットちゃん` のように `<wbr>` 要素タグを入れています。

#### 文章量に対してボックスが狭い場合

![約物のない文章が 7 行にわたって折り返されている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/54e53537-183d-65af-47eb-255d22045645.png)

`auto-phrase` 値が本領発揮するのは、このように文字列に対してボックスの幅が狭い場合です。`<wbr>` を記述していないにも関わらず、自然なフレーズの境界で折り返しが試みられています。しかし、前述した通り、「にゃんちゅう」の折り返し位置が不自然です。

この結果を見ると、`word-break: auto-phrase` はそれほど便利に使える代物ではなさそうな気がします。

`word-break: auto-phrase` は便利そうですが固有名詞の折り返し位置に弱いので、乱用するのは注意したほうがよいと思います。折り返して欲しくない位置に Zero Width Joiner (`&zwj;`) を入れて調整するくらいなら、`word-break: keep-all; overflow-wrap: anywhere` を指定した上で `<wbr>` を適切に挿入した方が期待する結果が得やすいのではないでしょうか。

### テキストがボックスをはみ出さないようにする

以下は Firefox での実行結果です。

![長い日本語と英語のそれぞれのテキストがボックスをはみ出すか折り返すかしている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/5342f6cd-c5d7-8386-2bde-01b76061e035.png)

余談ですが、Firefox と Chrome だとスラッシュを含む長い英字列の折り返し規則に差異があるようです。(0.) の CSS 指定なしの例を見ると分かりますが、Firefox では `https://example.com/path/to/path/to` の `/path` の直前で折り返しています。しかし Chrome では長い英字列 `LONGLONG_LONGLONG` と同様にはみ出してしまいます。

(1.) は `line-break: anywhere` を指定した例で、テキストがボックスからはみ出さないようになっています。しかし、禁則処理を無効にしたので日本語文が不自然な位置で折り返してしまうかもしれません。

(2.) は `word-break: break-all` を指定した例で、テキストがボックスからはみ出さないようになっています。しかし、このプロパティ値では英単語の途中で折り返してしまい、テキストとして英文が記述されている場合、混乱が生じる可能性があります。

(3.) は、`overflow-wrap: anywhere` を指定した例で、テキストがボックスからはみ出さないようになっています。日本語文は禁則処理を変更していないので自然な位置で折り返されています。英文も英単語の途中では折り返さず、単語間の空白の位置で折り返しがされています。

(4.) は、`overflow-wrap: break-word` を指定した例です。これは (3.) と同じ結果になりますが、`shrink-to-fit` なボックスでは折り返されなくなってしまうので `overflow-wrap: anywhere` を常に使っておけば良いと思います。

(5.) は、`overflow-wrap: anywhere` に加えて `word-break: keep-all` を指定した例です。これにより折り返し位置を調整しながら、テキストがボックスからはみ出さないようにすることができます。Firefox の例では「昔々」の直後で折り返していますが、これは「々」が折り返し可能位置だと解釈されているためです。Chrome ではそうはならず、『「にゃんちゅう」』の括弧閉じの直後で折り返されます。

## 関連記事

- [CSS wrap properties - CodePen](https://codepen.io/arcxor/pen/vYbwGoa)
- [CSS Text Module Level 4](https://www.w3.org/TR/css-text-4/#text-wrap)
- [Webブラウザの日本語改行問題 -改行を実現するHTML/CSS-（1） #JavaScript - Qiita](https://qiita.com/tamanyan/items/e37e76b7743c59235995)
- [CSS - word-break - とほほのWWW入門](https://www.tohoho-web.com/css/prop/word-break.htm)
- [CSS - overflow-wrap - とほほのWWW入門](https://www.tohoho-web.com/css/prop/overflow-wrap.htm)
- [CSS - line-break - とほほのWWW入門](https://www.tohoho-web.com/css/prop/line-break.htm)
- [CSS - text-wrap - とほほのWWW入門](https://www.tohoho-web.com/css/prop/text-wrap.htm)

# 折り返し位置をいい感じにする方法 2023

せっかく Chrome で `word-break: auto-phrase` が登場して盛り上がっているところ恐縮ですが、`word-break: keep-all; overflow-wrap: anywhere` を指定した上で `<wbr>` を適切に挿入するというアプローチの方が良いのではないかと思っているところです。

というわけで、`word-break: auto-phrase` よりも `word-break: keep-all` の方が最強な件をお伝えしてきました。異論は認めます。

# さいごに

そうそう、SP 表示と PC 表示で異なる折り返し位置を指定するのに `<br class="sp">` みたいに `br` 要素タグを使う方法はクソなのでぜひこの機会に滅んでください。異論は認めません。

なお、私はよく `display: inline-block` を使う方法を採用しています。これは昔からやっていたという理由（昔は `<wbr>` がまともに日本語文で機能しなかった）なので、これからは `word-break: keep-all; overflow-wrap: anywhere` に移行するかもしれません。

この方法にデメリットがあると主張されたい方がいればぜひコメントまでお寄せください。デメリットがあるのか不明です。

明日の [2023 年の MDN 翻訳 Advent Calendar](https://qiita.com/advent-calendar/2023/mdn-translation-community-japan) は `text-wrap` について解説予定です。

おわり。