CSSのtext-wrap: balanceで見出しの折り返しを整える

​​CSS​Playwright,日本語組版

見出しに text-wrap: balance を1行足すと、ブラウザーが各行の長さがそろうように折り返し位置を選び直します。最後の行に「を防ぐ」だけが残るような見出しが、同じ行数のまま、長さのそろった行になります。日本語の見出しでは単語の途中で折り返しやすくなるので、Chrome と Edge なら word-break: auto-phrase もいっしょに付けると、文節の切れ目で折り返せます。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。フォントは Noto Sans CJK JP を入れ、幅 360px、文字の大きさ 28px の h1 を Playwright で開いて、1文字ずつの位置から行ごとの文字列と幅を測りました。Firefox と Safari での表示、縦書きは試していません。各ブラウザーの対応バージョンは、互換性データ(@mdn/browser-compat-data 8.1.8)の値です。

text-wrap: balance を見出しに付ける

書き方は、見出しの要素に1行足すだけです。

css
h1,
h2 {
  text-wrap: balance;
}

検証環境で、「日本語の見出しがスマホで変な位置で折り返されるのを防ぐ」という見出しを幅 360px に入れ、指定なしと balance を比べました。

行 指定なし text-wrap: balance
1行目 日本語の見出しがスマホで(335.2px) 日本語の見出しがス(252px)
2行目 変な位置で折り返されるの(336px) マホで変な位置で折(252px)
3行目 を防ぐ(84px) り返されるのを防ぐ(252px)

指定なしでは、1行目と2行目に入るだけ詰め込み、3行目は「を防ぐ」の3文字だけになりました。balance では3行とも9文字、252px にそろいました。どちらも3行で、要素の高さも変わりません。CSS の仕様でも、balance は各行の余白がそろうように折り返し位置を選ぶ値で、5行以下なら行数を変えてはいけないと定められています。

英語の見出し「How to balance the line breaks of a heading with CSS」でも、指定なしでは3行目が「CSS」だけになり、balance では「How to balance」「the line breaks of a」「heading with CSS」の3行に分かれました。英語は単語の切れ目で折り返すので、行の長さが少しばらつきます。

1行に収まる見出しでは、balance を付けても何も変わりませんでした。サイトの見出しにまとめて付けておいても、短い見出しには影響しません。

日本語は word-break: auto-phrase と組み合わせる

上の表のとおり、balance だけでは「ス/マホ」「折/り返される」のように、単語の途中で折り返しました。長さをそろえることだけを優先するので、こうなります。

Chrome と Edge では、word-break: auto-phrase を足すと、文節の切れ目でだけ折り返すようになります。MDN では、言語ごとの分析をして、自然なフレーズの途中で改行しないようにする値と説明されています。

css
h1,
h2 {
  text-wrap: balance;
  word-break: auto-phrase;
}
3つの見出しを縦に並べた画面。点線の枠が幅360pxを示す。上の「指定なし」は「日本語の見出しがスマホで」「変な位置で折り返されるの」「を防ぐ」の3行で、3行目だけ短い。中の「text-wrap: balance」は「日本語の見出しがス」「マホで変な位置で折」「り返されるのを防ぐ」の3行で、長さはそろっているが単語の途中で切れている。下の「balance と word-break: auto-phrase」は「日本語の見出しが」「スマホで変な位置で」「折り返されるのを防ぐ」の3行
上から、指定なし、balance だけ、balance と auto-phrase。点線の枠は見出しの要素の幅(360px)

両方を付けると、「日本語の見出しが」「スマホで変な位置で」「折り返されるのを防ぐ」の3行になりました。行の幅は 224px、251.2px、280px で、balance だけのときほどぴったりはそろいません。そのかわり、どの行も文節の切れ目で終わっています。

word-break: auto-phrase だけを付けると、「日本語の見出しがスマホで」「変な位置で」「折り返されるのを防ぐ」となり、2行目が短く残りました。文節で区切る指定と、長さをそろえる指定は別のものなので、両方を付けたときにいちばん読みやすくなりました。

検証環境で、同じ見出しの要素に lang="en" を付けると、balance だけのときと同じ「ス/マホ」の折り返しに戻りました。auto-phrase を効かせるには、要素の言語が日本語(lang="ja")になっている必要があります。

要素の幅は縮まない

balance で変わるのは、行の中の文字の並びだけです。要素の幅は変わりません。検証環境では、balance を付けても h1 の幅は 360px のままでした。width: fit-content と max-width: 360px を指定しても、幅は 360px のままです。

上の画像の点線の枠のとおり、文字の右側に空きが残ります。画像では見出しに薄い水色の背景を付けていて、その空きにも色が付いています。text-align: center で中央寄せにしても、折り返し位置は左寄せのときと同じでした。

br で改行した見出しは、後ろの部分が整わなかった

見出しの途中に <br> を入れて、意図的に改行することがあります。<br> のあとの部分は、balance を付けても整いませんでした。

「猫の手も借りたいときに」のあとに <br> を入れ、続けて上と同じ見出しを入れると、<br> のあとは「日本語の見出しがスマホで」「変な位置で折り返されるの」「を防ぐ」となり、指定なしと同じ折り返しのままでした。仕様では、強制改行で区切られた行のまとまりは、それぞれ別に整えると定められています。仕様どおりなら <br> のあとも整いますが、検証環境の Chromium 153 ではそうなりませんでした。

行ごとに display: block の span で包むと、後ろの部分も整いました。

html
<h1>
  <span>猫の手も借りたいときに</span>
  <span>日本語の見出しがスマホで変な位置で折り返されるのを防ぐ</span>
</h1>
css
h1 {
  text-wrap: balance;
}

h1 span {
  display: block;
}
2つの見出しを縦に並べた画面。上の「br で改行」では、1行目「猫の手も借りたいときに」のあとが「日本語の見出しがスマホで」「変な位置で折り返されるの」「を防ぐ」となり、最後の行が短い。下の「行ごとに display: block」では、1行目のあとが「日本語の見出しがス」「マホで変な位置で折」「り返されるのを防ぐ」となり、3行の長さがそろっている
上は br で改行した見出し、下は行ごとに display: block の span で包んだ見出し。どちらも text-wrap: balance を指定

text-wrap は子要素に継承されるので、span に同じ指定を書き直す必要はありません。検証環境でも、body に text-wrap: balance を書くと、中の h1 の計算値が balance になり、長さのそろった3行で表示されました。

7行以上になると、Chromium では整わない

balance は、長い文章には効きません。MDN の text-wrap-style のページには、行数の多い文章では計算の負荷が高いため、Chromium では6行以下、Firefox では10行以下のときにだけ働くと書かれています。

検証環境で、1行に12文字入る幅の要素に、文字数を変えた文章を入れて試しました。

指定なしでの行数 balance を付けたとき
2行 7文字ずつにそろう
4行 10・10・9・9文字にそろう
6行 11・11・10・10・10・10文字にそろう
7行 指定なしと同じ(最後の行は2文字)
10行 指定なしと同じ(最後の行は2文字)

6行まではそろい、7行になると指定なしと同じ折り返しに戻りました。見出しや図のキャプションのような短い文章に付けるもの、と考えておくと迷いません。MDN でも、見出し、キャプション、引用のような数行の文章に向く値とされています。長い段落には、速さより見た目を優先して折り返す text-wrap: pretty という別の値があります。

text-wrap と text-wrap-style のどちらで書くか

text-wrap は、折り返すかどうかを決める text-wrap-mode と、どう折り返すかを決める text-wrap-style をまとめて指定する一括指定プロパティです。text-wrap: balance と書くと、text-wrap-mode は wrap、text-wrap-style は balance になりました。text-wrap-style: balance だけを書いても、同じ折り返しになりました。

互換性データでは、対応しているバージョンが次のように違います。

ブラウザー text-wrap: balance text-wrap-style: balance word-break: auto-phrase
Chrome・Edge 114 130 119
Firefox 121 124 対応なし
Safari(iOS を含む) 17.5 17.5 対応なし(Technology Preview のみ)

Chrome・Edge と Firefox では、一括指定の text-wrap: balance のほうが古いバージョンから対応しています(Safari はどちらも 17.5)。word-break: auto-phrase は互換性データで実験的な機能とされていて、Chrome と Edge だけが対応しています。Firefox と Safari では auto-phrase の指定は効かず、balance だけが効きます。

white-space は text-wrap-mode もいっしょに決める一括指定なので、あとから書くと、折り返すかどうかの指定(text-wrap-mode)が上書きされます。検証環境で、text-wrap: balance のあとに white-space: nowrap を書くと、text-wrap-mode が nowrap になり、見出しは折り返さずに1行のまま、幅 755.2px まで要素の外にはみ出しました。white-space: normal のときは、balance のまま3行に整いました。

​Posted by 86