見出しとかの日本語をいい感じの塊で自動改行するCSS

## 先に結論
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="xxoYOGR" data-pen-title="いい感じに自動改行するやつ（完成形）" data-user="mifumi323" 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/mifumi323/pen/xxoYOGR">
  いい感じに自動改行するやつ（完成形）</a> by 松田美文 (<a href="https://codepen.io/mifumi323">@mifumi323</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
リサイズできるようにしたから横幅変えて挙動を確認してみてね。

### ポイント
- 大きな塊単位で改行して、それで収まらなければ小さな塊で順次改行していくよ
- `display: inline-block;`のスタイルを当てた`span`タグで囲った部分が一つの塊になるよ
- `span`タグの入れ子でより細かい塊を作ってるよ
- スペース(特に全角スペース`　`)は`span`要素の端に来ないようにする必要があるよ
- `overflow-wrap: anywhere;`と`word-break: normal;`のスタイルの組み合わせで、最小の塊より幅が狭くなったときの改行を制御してるよ

ここから下は、もうちょっと詳しく知りたいって人向けです。

## 前書き
さて皆さん、映画『それいけ！アンパンマン　ばいきんまんとえほんのルルン』はご覧になりましたか？
エンジニア魂を揺さぶる今作は大人にも評判が良く、子供連れの少ない夕方・夜間の上映も一部映画館で行われています。

https://anpan-movie.com/2024/

見ましたね？感動しましたね？当然ブログに書きますよね？
もちろん見出しは「それいけ！アンパンマン　ばいきんまんとえほんのルルン」です。

特に深く考えずに書くとこんな感じでしょうか。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="XWLZKve" data-pen-title="いい感じに自動改行しないやつ" data-user="mifumi323" 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/mifumi323/pen/XWLZKve">
  いい感じに自動改行しないやつ</a> by 松田美文 (<a href="https://codepen.io/mifumi323">@mifumi323</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

![いい感じに自動改行しないやつ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212471/dd4683fa-ae11-2133-55ca-5481f309d9d5.png)
見出しなのに`div`タグだとか、CSSが少々恣意的だとかはこの際置いとくとして、見栄えがちょっと残念なことになっています。

1行目が「それいけ！アンパンマン　ばいきんまんとえ」、2行目が「ほんのルルン」です。
「えほんのルルン」の「え」だけが1行目に残り、2行目がほんのちょっとだけルルンみたいな印象になってしまいました。
一応最初からちゃんと読めばちゃんと読めますが、ぱっと見の印象は微妙ですね。
どうせ2行に分かれるなら、1行目を「それいけ！アンパンマン」、2行目を「ばいきんまんとえほんのルルン」といった具合にきりよくしたいところです。
もっと狭くなって3行になるようなことがあっても「えほんのルルン」がぶち切れるようなことは極力避けたいですね。

というわけで、今回の目標は、「見出しとかの日本語をいい感じの塊で自動改行すること」です。

## 先行事例
テキストをきりのいいところで改行するという点で、以下の記事が似たようなことをやっています。

https://qiita.com/tamanyan/items/e37e76b7743c59235995

今回私がやったことは、この記事の「[解決策3. \<span\> + display: inline-block;](https://qiita.com/tamanyan/items/e37e76b7743c59235995#%E8%A7%A3%E6%B1%BA%E7%AD%963-span--display-inline-block)」を基にアレンジしたものとなります。

先行事例を素直に実装すれば、以下のようになります。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="yLdvjpo" data-pen-title="それなりに自動改行するやつ" data-user="mifumi323" 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/mifumi323/pen/yLdvjpo">
  それなりに自動改行するやつ</a> by 松田美文 (<a href="https://codepen.io/mifumi323">@mifumi323</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

![それなりに自動改行するやつ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212471/2abfb483-970b-6b14-0328-06883a3d29c3.png)

悪くはないです。「えほんのルルン」は切れてませんしね。
でも、欲を言えば、「ばいきんまんと」一緒にいさせてあげたいです。

## もっときりのいいところで改行する
そういうことで、アレンジが必要なのですが、結局やることは同じです。
文字単位で半端な場所で切れてほしくないから、`span`で囲って塊にしたのです。
塊単位でも半端な場所で切れてほしくないなら、更に`span`で囲って塊にするのです。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="QWXQJRb" data-pen-title="CodePen Home
ある程度自動改行するやつ" data-user="mifumi323" 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/mifumi323/pen/QWXQJRb">
  CodePen Home
  ある程度自動改行するやつ</a> by 松田美文 (<a href="https://codepen.io/mifumi323">@mifumi323</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

![ある程度自動改行するやつ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212471/4b4896c3-9482-f840-3274-be53e4b55562.png)

かなりいい感じですね。
横幅を色々変えて様子を見てみましょう。

![「ばいきんまんと」を表示できないほど幅を狭めた](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212471/832f826e-35c8-4aba-768e-10144c159fc5.png)

「ばいきんまんと」が行に収まりきらなくなって改行されました。
元記事でも[問題点](https://qiita.com/tamanyan/items/e37e76b7743c59235995#span--display-inline-block%E3%81%AE%E5%95%8F%E9%A1%8C%E7%82%B9)と言われていた挙動です。
塊を一つの四角形として扱っている以上、これはもうどうにもなりません。
こんなに狭いんだから、読めるだけでも御の字です。

![限界まで幅を狭めた](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212471/b079ed29-d6e8-a8b5-be07-123ce78caccd.png)

そ…ι…け…ア…パ…マ…？
限界まで幅を狭めたら、完全に破綻して読めなくなってしまいました。
もはやレイアウトどころではないと思いますが、一応読めるようにだけはしておきたいです。
目指せ御の字！

## 文字の折り返しの調整
以下の記事を参考にして、調整してみます。

https://ics.media/entry/240411/

```css
body {
  overflow-wrap: anywhere; /* 収まらない場合に折り返す */
  word-break: normal; /* 単語の分割はデフォルトに依存 */
  line-break: strict; /* 禁則処理を厳格に適用 */
}
```

`overflow-wrap: anywhere;`は、行内に収まらない場合には、単語の途中だろうが禁則処理があろうが問答無用で改行します。
`word-break: normal;`は、英語は英単語単位で、日本語は文字単位で、みたいな指定です。
`line-break: strict;`は、極限まで狭い環境で厳密にするのも、という気がするので、採用しないことにします。

そうやってできたCSSがこちら。最初に書いた結論と同じものになります。

```css
span.line-chunk {
  display: inline-block;
  overflow-wrap: anywhere;
  word-break: normal;
}
```

![限界まで幅を狭めても大丈夫](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212471/e24c2a98-5d7f-49b0-3180-eece64165d6e.png)

縦長になりすぎてスクショ途中までになってますが、ちゃんと文字が収まっています。

## スペースの扱い
今回のサンプルテキストは希代の名作「それいけ！アンパンマン　ばいきんまんとえほんのルルン」でした。
前半と後半の間にある全角スペース「　」はどの塊に入るのでしょうか。
どっちかに入れて確かめてみましょう。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="BagYXxj" data-pen-title="いい感じに自動改行するけどスペースがおかしいやつ" data-user="mifumi323" 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/mifumi323/pen/BagYXxj">
  いい感じに自動改行するけどスペースがおかしいやつ</a> by 松田美文 (<a href="https://codepen.io/mifumi323">@mifumi323</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

![いい感じに自動改行するけどスペースがおかしいやつ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212471/77d3ef69-8a3d-0fbd-0c0a-2f6e2bf7f624.png)

改行位置は問題ありませんが、文字の位置がずれてしまいました。
おそらく、`span`要素の大きさは全角スペース込みで計算し、センタリングする文字列の大きさは全角スペース抜きで計算しているものと思われます。
なので、全角スペースは塊の外、`</span>`と`<span class="line-chunk">`の間に入れるのがよいでしょう。

なお、半角スペースでは同様の問題は起こらないので、半角スペース以外のスペースを認めないという運用もありかと思います。

## 英語の場合
さて、ここまでサンプルコードにはだいたい英語も併記してきたわけですが、英語の場合はちょっとシンプルになります。
やること自体は日本語の場合とほぼ変わらないのですが、英語はもともとワードラップが効くので、単語まで`span`で囲う必要はありません。
また、半角スペース以外のスペースを使おうという発想も日本語ほどには出てこないと思うので、スペースのケアも考えなくて済みます。

## span入れるのめんどくさくない？
めんどくさいです。
…が、段階的に塊を作っていく都合上、形態素解析で機械にお任せなんてことも難しいのではないかと思っています。
このあたりの手作業を楽にする方法とかも紹介できればと思うのですが、まあ、[後日書けたら書く（関西弁）](https://shakai.kanto-gakuin.ac.jp/news/1936/)ということで。

## おわりに
全く同じ発想をどこかで見たことあるような気がするのですが、思い出せません。
ご存じの方がいらっしゃいましたらコメントで教えていただけると幸いです。

## 参考リンク（再掲）
https://anpan-movie.com/2024/

https://qiita.com/tamanyan/items/e37e76b7743c59235995

https://ics.media/entry/240411/