22
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2023-12-13

はじめに

この記事は 2023 年の MDN 翻訳 Advent Calendar 向けに作成したものです。

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

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

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

他にも関連しそうなものとして white-space プロパティや hyphens プロパティもありますが、折り返しを制御するものとして上記 4 つのプロパティがあります。

text-wrap プロパティは CSS Text Module Level 4 で策定された最新のプロパティで、他のプロパティとは少しやれることが異なるのと、text-wrap だけで記事が書けるくらいには情報量がありそうなのでこの記事では扱わないことにします。

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

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 では更に manualauto-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 が実装されました。この記事では、auto-phrase がどのくらい使えるものなのかについて後述します。

overflow-wrap (旧 word-wrap) プロパティ

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

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

line-break プロパティ

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

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

ブラウザでの動作確認

See the Pen CSS wrap properties by arcxor (@arcxor) on CodePen.

折り返し位置の調整

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

word-break: auto-phrase だと「にゃんちゅう」が1文字目の「に」の直後で折り返している。word-break: keep-all だときれいに「にゃんちゅう」の単語直前で折り返している。

(1.) から (5.) は line-break の動作確認結果なのでそれほど重要ではありません。

(6.) の word-break: auto-phase をみると、「にゃんちゅう」の 1 文字目「に」の直後で折り返してしまっています。これは期待する結果ではありません。

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

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

窓ぎわのトットちゃん

「窓ぎわのトットちゃん」という例文の場合。(6.),(7.),(8.) では「トットちゃん」の直前で折り返している。

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

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

約物のない文章が 7 行にわたって折り返されている。

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

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

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

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

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

長い日本語と英語のそれぞれのテキストがボックスをはみ出すか折り返すかしている。

余談ですが、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 ではそうはならず、『「にゃんちゅう」』の括弧閉じの直後で折り返されます。

関連記事

折り返し位置をいい感じにする方法 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 Calendartext-wrap について解説予定です。

おわり。

22
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?