overflow-wrap: break-word; や word-break: break-all; が万能の改行処理だったなら、こんなに苦労していない

## はじめに
今回解決したいのはこれです。
<img width="1216" alt="スクリーンショット 2020-01-20 21.44.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/92ae275f-2ba0-9230-689e-c9857f9ed7ae.png">
「**`overflow-wrap`かけたのに改行されないしテーブルwidthもなんか勝手に伸ばされちゃってる問題**」です。

こんなんHTML / CSSの初歩中の初歩じゃんwwwという方は、どうぞごゆるりとブラウザバックしてやってくださいませ…

「それ地味に悩んでた！」という方がもしいらっしゃいましたら、少しでも助けになれれば嬉しいです。というか一緒に悩みましょう。

あ、でも、もしそんな方が本当にいたら、こんなことに悩むよりも、
**「全半角記号のブラウザテストだけ許容する」という呪文を唱えた方が5億倍早い**です…というネタバレだけ先にしておきますね＞＜

### もくじ

当記事は、以下の内容に関するメモ書きです。


- CSSの改行処理プロパティのメリデメ
- 上記問題の暫定解決方法


対象のCSSプロパティは以下の通りです。

- `overflow-wrap: break-word;`
- `word-wrap: break-word;`
- `word-break: break-all;`
- `word-break: break-word;`

### 環境

記事のスクショは、下記環境で作成しています[^1]。

| OS | ブラウザ | 
|:-----------|------------|
| MacOS 10.15      | Chrome       | 


[^1]: 暫定解決方法については、Windows 10やIE, Edge, FireFoxでも試行しましたが、間違い等ありましたら申し訳ありません。

## overflow-wrap: break-word;

<img width="1429" alt="スクリーンショット 2020-01-22 23.56.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/9280373b-4abe-2192-210d-f7b98ef1714f.png">


こんな時にオススメ！：
「コンテナから**なるべくはみ出したくはない**けど…**禁則処理[^2]もなるべく入れたい**し…**英単語も可能な限り綺麗な状態で表示させたい**なぁ〜！」という時。

[^2]: 句読点、とじかっこなどの記号が行頭に来ないようにするルール。https://ja.wikipedia.org/wiki/%E7%A6%81%E5%89%87%E5%87%A6%E7%90%86

メリット：

- ブラウザ：Chrome, Edge, IE, FireFoxなど、主要ブラウザで対応
- 禁則処理：可能な限り保たれる
- コンテナ（テキストの表示領域）幅より長い英単語：強制的に折り返される
- 記号の連続の折り返し：対応

デメリット：

- テーブル内のセルでは適用されない…………（※詳細下記）

処理の詳細は、[MDNのCSSリファレンス](https://developer.mozilla.org/ja/docs/Web/CSS/overflow-wrap)で以下のように定義されています。
> インライン要素に対して、テキストが行ボックスをあふれないように、ブラウザーが不可分の文字列の途中で改行を入れるかどうかの設定を適用します。

下記サイトの説明がより分かりやすいです。

> 単語の途中で折り返さないと行ボックスの幅からあふれてしまうときのみ、その単語の途中で折り返します。単語の途中で折り返しが発生するのは、その単語の幅が行ボックスの幅より大きい場合のみとなります。つまり、可能な限り禁則処理が保持され、可能な限り単語途中での折り返しを避けることができます。
https://w3g.jp/blog/confusing_word-break_word-wrap より

`overflow-wrap: break-word;` は、「単語内改行をしないこと」より「コンテナ幅」を優先する設定です。次に入力される単語がコンテナ幅の残りを超えそうな場合、単語内で改行しないように単語ごと次の行に送る制御をします。

<img width="777" alt="スクリーンショット 2020-01-23 0.01.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/3bf6339e-950e-f234-a7b5-f95a8179d31a.png">

上記の処理だけでは対応できない場合、例えば1語の長さがコンテナ幅を超えてしまう場合は、単語の途中で折り返すことを許容して、コンテナ幅に収めるという設定です。
たとえば、世界一長い地名`Tetaumatawhakatangihangakoauaotamateaurehaeaturipukapihimaungahoronukupokaiwhenuaakitanarahu`が入力されてコンテナを超えてしまうような場合、単語途中での折り返しが発生します。




逆に、「コンテナ幅」より「単語内改行をしないこと」を優先させたい場合は、`overflow-wrap: normal; ` を設定します（デフォルトの値なので設定しなくても大丈夫です）。
`Tetaumatawhakatangihangakoauaotamateaurehaeaturipukapihimaungahoronukupokaiwhenuaakitanarahu`が入力された場合には、コンテナ幅をはみ出すことを許容して、単語内の改行を防ぐ結果になります。

<img width="800" alt="スクリーンショット 2020-01-23 0.01.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/5ed15cb9-b8ce-047f-72c7-014e102fb1a2.png">


※ただし、`overflow-wrap（word-wrap）`プロパティは**テーブル内のセルには使用できません**。

<img width="1400" alt="スクリーンショット 2020-01-23 0.06.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/178c4d55-badd-3292-fcdd-672db809fe9b.png">

詳しく言うと、`overflow-wrap（word-wrap）`プロパティはテキストの長さとコンテナ幅を計算して折り返し可否を決めていますが、テーブルのデフォルトCSS設定である自動レイアウトアルゴリズム`table-layout:auto;`も、中身のテキストによってレイアウトを計算するプロパティです。
このため、重ね掛けすると`overflow-wrap（word-wrap）`側の計算がうまく効かなくなってしまうようなのです。

## word-wrap: break-word;

`word-wrap`プロパティは`overflow-wrap`プロパティの前身です。
[CSS3の仕様書](https://drafts.csswg.org/css-text-3/#propdef-word-wrap)では現在、後方互換性のために`overflow-wrap`プロパティを使用する実装者は対応する`word-wrap`プロパティも併記することを推奨しています。

## いやテーブルで改行したいねんな！！！！
`overflow-wrap`や`word-wrap`は正直すごい。天才。

日本語も英語も記号も良きところで良き感じに改行してくれる。もうこれがベストプラクティス。
いや普通の実装だったらほんと`overflow-wrap`先生に任せて、副担に`word-wrap`おじいちゃんをつけておいてあげればまず間違いない。分かってる。

でもこれで満足する人間だったらQiita書いてないんだな。

今回の課題はこれです（再掲）。
<img width="1216" alt="スクリーンショット 2020-01-20 21.44.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/e876b45e-a823-4e00-cbac-eb1afddc7412.png">
「**そんな天才的な`overflow-wrap`先生をかけたのに改行されないし、テーブルwidthもなんか勝手に伸ばされちゃってる問題**」です。

自動計算アルゴリズムかなんか知らんが、やってくれやがりましたな…

大体のフォームやアンケートや個人情報ページなどには、文字数確定部分だけじゃなくて自由記述欄もあったりするかと思うのですが、
生半可にテキスト文字数可変項目を含むテーブルを作ると、自由記述欄に！マークが100文字とか入ったらレイアウトが死ぬ可能性が発生しちゃう…

次に紹介するのは、そんな逆境で出会った、悪魔のようなプロパティです。
どうぞ。

## word-break: break-all;

<img width="1417" alt="スクリーンショット 2020-01-22 23.44.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/e90dcc1c-5f55-0964-9963-7df7c37b9735.png">

こんな時にオススメ！：
「**死んでも絶対レイアウト崩したくねえ〜〜〜〜！！！！！！**行頭の句読点とか気にしないし、英語とかマジぶつ切りになってもいいから、**とにかく絶対にコンテナからはみ出させねえ（強い意志）**」という時。

メリット：

- ブラウザ：Chrome, Edge, IE, FireFoxなど、主要ブラウザで対応
- コンテナ幅より長い英単語：強制的に折り返される

デメリット：

- 禁則処理：ほとんど解除されてしまう
- コンテナ幅より短い英単語で、単語全体を次の行に送れば途中で改行を防ぐことができる場合であっても、テキストがコンテナから溢れたところで強制的に折り返してしまう
- 一部記号（！や？など）の連続に対応していない……

[MDNのCSSリファレンス](https://developer.mozilla.org/ja/docs/Web/CSS/word-break)では以下のように定義されています。

> 単語中などでの文字の改行に関する禁則処理を解除し、どの文字の間でも改行するようにします。


みんな大好き`word-break: break-all;`。**何があっても強制改行**してくれます。心強い。
英単語が入るとめちゃめちゃ読みづらいのですが、正直日本語は単語の区切れ目でなくても改行できる言語なので、そんなに気にしなくても…（悪魔のささやき）
`overflow-wrap`や`word-wrap`の細かいプロパティでこちゃこちゃ悩みたくねえ！！とにかく「単語内改行をしないこと」より「コンテナ幅」を最優先したい！という場合は、結局これを選んでしまうのです…（悪魔のささやき）
しかし禁則処理の（ほぼ）全解除なので、日本語でも**句読点が行頭に来る**など、若干気になる人は気になる処理になってしまいます。

ちなみに、`overflow-wrap（word-wrap）: break-word;`と`word-break: break-all;` を重ね掛けした場合は、`word-break: break-all;` が優先されてしまうそうです。圧倒的パワー。

## 何があっても強制改行と言ったな？あれは嘘だ

さて、禁則処理や英語をかなぐり捨てて「「「力」」」を手に入れた我々なので、きっと理想のテーブルが出来上がったことでしょう！！！！
<img width="1211" alt="スクリーンショット 2020-01-20 22.31.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/5deea7cf-f0d2-139a-13e6-7b579263ce11.png">
そうですね、無情ですね。

詳しい理由は分かりませんが、[CSS3の仕様書](https://drafts.csswg.org/css-text-3/#propdef-word-break)でも、`word-break: break-all;`は以下のように説明されています。
> Breaking is allowed within “words”
> （「語句」内での改行を行う）

[stackoverflow](https://stackoverflow.com/questions/43396861/the-word-break-style-is-not-applying-on-text-with-symbol)でも「記号＄が`word-break: break-all;`で改行されない」という質問に対して、以下のような回答がついています。
> ユニコードで「文字」「数字」ではなく「記号」として分類されているものは、禁則処理が弱いのでは

`word-break: break-all;` でも、テーブル内で一部記号の連続を改行することは難しいのかな…
としょげたその時、

天使が現れました。

## word-break: break-word;

はい天才。完成。
<img width="1194" alt="スクリーンショット 2020-01-23 0.18.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/fe8e7726-33fa-2049-b96e-0d7e86bbe9cd.png">

こんな時にオススメ！：
「**IEとEdgeは捨てた。改行させてくれ**」

メリット：

- 禁則処理：**可能な限り保たれる！**
- コンテナ（テキストの表示領域）幅より長い英単語：**強制的に折り返される！！**
- 記号の連続の折り返し：**対応！！！**
- **テーブル内のセルにかけてもちゃんと効く！！！！**

デメリット：

- **ブラウザ：IEとEdgeには非対応**

公式では以下のように定義されています。

> 行内で適切に改行できる場所が他にない場合に限って、単語の途中でも改行するようにします。
（https://developer.mozilla.org/ja/docs/Web/CSS/word-breakより）


いやこれがマジでやりたかった（**なおIEとEdgeは非対応**）。
これがマジでやりたかったんだが、`word-break`プロパティの中でもなぜかこれだけ**IEとEdge非対応**なんだな…………
IEとEdgeのことだけ都合よく記憶喪失になった人にだけ使用が許される、天使のように天真爛漫純粋無垢かつ無情なプロパティ。

## 暫定解決方法
このようにいろいろ試行錯誤しまして、以下条件での暫定の解決方法を見つけました。

- 主要ブラウザ（Chrome,  FireFox, IE, Edge）対応
- 英語や句読点にはなるべく禁則処理を入れたい
- コンテナ幅を超える英単語だけは単語の途中で折り曲げても良い
- 記号の連続も折り返したい
- とにかく枠を広げたくない

無理やろ…と思いましたが、案外いけたんですよね。

<img width="1085" alt="スクリーンショット 2020-01-20 23.36.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/4bb4625d-6389-2cf2-e75a-4d5d25eb45ee.png">

**tdの中にdivを作成し、クラス属性に以下を設定する**

- **width**
- **`overflow-wrap: break-word;`**

これだけでした。なんて簡単なんだ…divだったのか…
tdにwidth, `overflow-wrap: break-word;`を直接指定してもうまくいかなかったです。`table-layout: auto;`のせいですかね…

## おわりに

試行錯誤してやっと見つけたわりにはしょぼい解決法ですし、テーブル設計的に一部のtdだけ中にdiv入れるのってどうなの？とも思うのですが、自分はちょっとこれで力尽きました。。
HTML / CSSに詳しい人にぜひイケてるHTML設計アドバイス欲しいです…
「暫定解決方法でも、まあ、ウン…大丈夫だよ！動くよ！（生暖かい目）」ということであれば、そっといいねしていただけると嬉しいです😂

お読みいただきありがとうございました！



## 暫定解決方法②（2020/01/29追記）

｢**`table-layout: auto;`を`table-layout: fixed;`に変更する**｣

今回やりたいこと自体は`overflow-wrap: break-word`の章でちらっと触れたtable-layoutプロパティを
auto（デフォルト）→fixedに変更することで、td配下にdivの入れ子を作らなくても実現可能です！むしろこっちの方が簡単でした！
（コメント欄で検証いただいています。@yshimizu125 さん、ありがとうございます！）

ただし、デメリットとして
｢既存サイトのtableのCSSを変えると、影響範囲が大きくなってしまう｣
という理由があり、自分は使用できなかったのですが、
新規のHTMLページを作る予定で、`table-layout: auto;`にする必要がない人は、初めから`table-layout: fixed;`をtableのCSSとして設定しておくと良いかもしれません！