結局テキストの折り返しってどの指定をすればいいの？

##  これは何

[CSS Advent Calendar 2022](https://qiita.com/advent-calendar/2022/cascading_style_sheets)の参加記事です！

CSSでテキストの折り返し指定をする時に毎回「結局何を指定すればいいんだっけ..」と悩むので、折り返し指定について改めて調べてまとめました。

## そもそもなぜ折り返し指定が必要なのか

ボックスやブラウザサイズに対して溢れるようなテキストがある時に、表示崩れの原因になるためです。

例えば横幅375pxのスマートフォンでサイトを閲覧していて、それよりも長いテキストが折り返されずに表示された場合、不要な横スクロールが発生したりテキスト全体を表示させるために画面が小さく表示されてしまうことがあります。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/72e8ce58-85c7-312c-dfbb-388880447a2b.png)

そのため、ブラウザのデフォルトの改行規則では改行されないテキストが入り得る箇所には折り返しの指定をする必要があります。

## デフォルトの改行規則

では、デフォルトの改行規則ではテキストの折り返しがどのようになるのかを見ていきます。

テキストの折り返しに関する指定を何もしていないのが、「デフォルト」と文頭に書いてあるテキストです。
比較のために、禁則処理を`line-break: anywhere;`でなしにしたものと並べています。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="YzvvYwd" data-user="kabechiyo13" style="height: 300px; 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/kabechiyo13/pen/YzvvYwd">
  折り返し</a> by かべちよ (<a href="https://codepen.io/kabechiyo13">@kabechiyo13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

ブラウザやOSによって見え方が異なるかもしれないので、`Result`のスクリーンショットも掲載しておきます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/2a218431-8404-e415-5e4d-76e9e352bed6.png)

まずは、「pneumonoultramicroscopicsilicovolcanoconiosis」のような長い英単語やURLが折り返されずにボックスからはみ出していることがわかります。
また、禁則をなくしたテキストと見比べると「、」のような約物が行頭に来ないようになっていたり、「consectetur」のような英単語の途中で改行が入らないよう単語の区切りで改行が入っていることがわかります。

## 折り返しに関する指定について

テキストの折り返しに係るCSSの指定は、先ほど使用した`line-break`の他に、`word-break`と`overflow-wrap`があります。

### 各プロパティの違い

- `line-break`
    - テキストの禁則処理を指定します
- `word-break`
    - テキストがコンテンツボックスからあふれる時に、その位置で改行するかどうかを指定します
    - 単語を分割せずに改行することができる場合でも、単語を分割します
- `overflow-wrap`
    - テキストがコンテンツボックスからあふれる時に、文字列の途中で改行するかどうかを指定します

### 各プロパティの指定の比較

これらのプロパティを利用した指定を[MDN](https://developer.mozilla.org/ja/)を参考に表に整理しました。

:::note warn
`word-break: break-word;`は非推奨になっているため含めていません
:::

| プロパティ | 値 | テキストが溢れるときに改行する | 改行位置 |
|:--|:--|:--|:--|
| line-break | auto | 一部改行しない | 改行規則に則って改行する |
| line-break | loose | 一部改行しない | 改行規則に則って改行する |
| line-break | normal | 一部改行しない | 改行規則に則って改行する |
| line-break | strict | 一部改行しない | 改行規則に則って改行する |
| line-break | anywhere | **改行する** | 文字が溢れる位置で改行する |
| word-break | normal | 一部改行しない | 改行規則に則って改行する |
| word-break | keep-all | 一部改行しない | 改行規則に則って改行する |
| word-break | break-all |  **改行する**  | 文字が溢れる位置で改行する |
| overflow-wrap | normal | 一部改行しない | 通常の分割位置でのみ改行する |
| overflow-wrap | break-word | **改行する** | テキストが溢れるときは、できるだけ単語を分割しないように改行し、できない場合のみ分割できない文字列で改行する |
| overflow-wrap | anywhere | **改行する** | テキストが溢れるときは、できるだけ単語を分割しないように改行し、できない場合のみ分割できない文字列で改行する |

つまり、テキストが溢れる時に改行するのは、`line-break: anywhere;` `word-break: break-all;` `overflow-wrap: break-word;` `overflow-wrap: anywhere;`の4つになります。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="YzvvYgK" data-user="kabechiyo13" style="height: 300px; 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/kabechiyo13/pen/YzvvYgK">
  改行</a> by かべちよ (<a href="https://codepen.io/kabechiyo13">@kabechiyo13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

それぞれの指定をしたテキストを見比べてみると、どれもテキストがはみ出さないようにはなっていますが、`line-break: anywhere;` `word-break: break-all;`は通常は改行しないテキストでも行末に来たら改行していますが、`overflow-wrap: break-word;` `overflow-wrap: anywhere;`はなるべく改行しないよう単語の前後に改行が入っています。

また、「、」が」が文頭にこないようにする禁則が`line-break: anywhere;`では効いていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/84be3866-6703-eeb3-eef8-ca2747b4075a.png)

### `overflow-wrap: break-word;` `overflow-wrap: anywhere;`の違い

では、`overflow-wrap: break-word;` `overflow-wrap: anywhere;`の違いはなんなのか、MDNでは以下のように記述されています。

> anywhere
あふれることを避けるために、行内にその他の分割可能な位置がない場合、その他の分割できない文字列 — 長い単語や URL — が任意の場所で分割されることがあります。分割位置にハイフン文字は挿入されません。コンテンツの最小固有寸法を計算する時には、単語分割によって導入された折り返し可能位置が考慮されます。

> break-word
anywhere の値と同様に、行内にその他の分割可能な位置がない場合、通常は分割可能でない単語が任意の場所で分割されますが、コンテンツの最小固有寸法を計算する時に、単語分割によって導入された折り返し可能位置が考慮されません。

2つの違いは「コンテンツの最小固有寸法を計算する時」に「単語分割によって導入された折り返し可能位置が考慮されるかどうか」のようです。

要は`min-width`や`min-height`を計算するときに「本来は分割できない位置で入れた改行の位置」でサイズを決めるか、本来改行されていない状態で決めるかということみたいです。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="YzvveKP" data-user="kabechiyo13" style="height: 300px; 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/kabechiyo13/pen/YzvveKP">
  Untitled</a> by かべちよ (<a href="https://codepen.io/kabechiyo13">@kabechiyo13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

実際に本来改行できない1単語である`pneumonoultramicroscopicsilicovolcanoconiosis`にそれぞれの値を指定して比較してみると、`anywhere`を指定した方では改行位置に合わせた`width`になり、`break-word`を指定した方では`pneumonoultramicroscopicsilicovolcanoconiosis`に合わせたサイズになっています。

## 折り返し指定をするときの注意点

これらを踏まえると、溢れないように改行はしてくれつつなるべく単語間に改行を入れないでくれる`overflow-wrap: anywhere;`を指定するのが良さそうですが、いくつか注意点があります。

まず、要素が`Flexbox`の時や`position:absolute`が指定されている時は`width`を指定する必要があります。

:::note
`Flexbox`で`flex: 1`を指定している場合など、要素の幅が内容によらず決まるときはwidthを指定しなくても大丈夫です
[コメント](https://qiita.com/kabechiyo13/items/e77c9e9e5ef36b25f05f#comment-09bec5ec0e8257bc69bc)をいただき追記しました。
:::

また、テーブルの要素の時は`table-layout: fixed;`を指定する必要があります。

### ブラウザのサポート状況

[Can I Use](https://caniuse.com/?search=overflow-wrap)で確認すると`word-break`と`overflow-wrap: break-word;`は殆どのモダンブラウザの最新版でサポートされていますが、`overflow-wrap: anywhere`はSafariとSafari on iOS、Opera Mobileの最新版でサポートされていないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/f4c4099f-3a83-15bb-abec-3fbc94ada64a.png)

ただ、筆者がSafari, Safari on iOSで試したところ`overflow-wrap: anywhere`が効いていたことと、Apple Evangelist のJen Simmons氏がTwitterでサポートを追加したと回答していることから、Safari, Safari on iOSでも利用できそうです。

https://twitter.com/jensimmons/status/1515042940783104002?s=20&t=eRq4k6jnKo67sPzBG_E5_Q


## 結論

以上を踏まえると、

- ✅ テキストが溢れる時に改行してくれる
- ✅ できるだけ単語に改行を入れない
- ✅ 殆どのモダンブラウザの最新版でサポートされている

ことから、`overflow-wrap: break-word;`を指定するのが良さそうです。

ただし、`Flexbox`の時や`position:absolute`の時は`width`を指定する必要があることとテーブル要素の時は`table-layout: fixed;`を指定する必要があるため、単語間に改行が入ることを許容するのであれば

- ✅ テキストが溢れる時に改行してくれる
- ✅ 殆どのモダンブラウザの最新版でサポートされている

`word-break: break-all;`も良さそうです。

:::note
もし他にも折り返しについておすすめな指定方法やサポート状況のことなどご存知の方がいらっしゃいましたら編集リクエストやコメントで教えていただけると助かります！
:::


## 参照

https://developer.mozilla.org/ja/docs/Web/CSS/line-break

https://developer.mozilla.org/ja/docs/Web/CSS/word-break

https://developer.mozilla.org/ja/docs/Web/CSS/overflow-wrap

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Text/Wrapping_Text

https://caniuse.com/?search=overflow-wrap