CSSで、日本語のかっこや句読点の詰め方を整える方法

​​CSS​Playwright,フォント,日本語組版

日本語のかっこや句読点の詰め方は、CSS の text-spacing-trim プロパティで変えられます。Chrome と Edge では、」「 のように隣り合ったかっこの間の空きは、何も書かなくても半分に詰まります。行頭のかっこも詰めたいときは trim-start、詰めずに昔の見た目に戻したいときは space-all を指定します。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。フォントは Noto Sans CJK JP と IPAゴシックを入れ、横書きのページを Playwright で開いて、1文字ずつの幅を測りました。縦書き、Chrome 以外のブラウザー、Windows や macOS に入っているフォントでの表示は試していません。各ブラウザーの対応バージョンは、互換性データ(@mdn/browser-compat-data 8.1.8)の値です。

何もしなくても、隣り合うかっこは詰まる

かっこや句読点の多くは、漢字と同じ全角の幅を持ちながら、字形の片側に空きがあります。そのため、」「 や )、 のように並ぶと、空きが重なって間が広く見えます。

text-spacing-trim の初期値 normal は、この重なった空きを半分に詰めます。CSS の仕様では、初期値は normal で、子要素に継承されると定められています。

検証環境で、何も指定しない段落と space-all を指定した段落の、1文字ずつの幅を測りました。1.00 が全角、0.50 が半角です。

段落に入れた文字列は 「東」「東」(東)、東。 です。

並び 測った文字 指定なし(normal) space-all
」「 「 0.50 1.00
」( ( 0.50 1.00
)、 ) 0.50 1.00
)、 、 1.00 1.00
行全体 12文字の幅の合計 10.51em 12.01em

閉じかっこのあとに始めかっこが来ると始めかっこが半角になり、閉じかっこのあとに読点が来ると閉じかっこが半角になりました。12文字の行が、1.5文字分短くなっています。

2つの段落を縦に並べた画面。上は「指定なし(初期値の normal)」で、「猫の手」を借りたい。(忙しいときの言い方)「はい。」「いいえ。」という文章の、句点と始めかっこ(。()、閉じかっこと始めかっこ()「 と 」「)、句点と閉じかっこ(。」)の間が詰まっている。下は「text-spacing-trim: space-all」で、同じ文章のかっこや句点の間に、それぞれ半角ほどの空きがある
上が初期値、下が space-all。初期値では、句点とかっこ、かっことかっこが続くところが詰まる

句点と閉じかっこが続く「はい。」の 。」 でも、句点が半角になりました。どの組み合わせで詰めるかの規則は、MDN の「全角幅の約物の折り畳み」の節にまとめられています。

詰めずに、すべてのかっこと句読点を全角のまま並べたいときは、space-all を指定します。

css
body {
  text-spacing-trim: space-all;
}

行頭のかっこも詰めるには trim-start

初期値の normal では、行の頭に来た始めかっこは全角のままです。かっこの左に半角の空きが残るので、ほかの行より半文字分、右にずれて見えます。行頭の始めかっこも半角にして、行の左端をそろえたいときは trim-start を指定します。

css
body {
  text-spacing-trim: trim-start;
}

段落の最初の行の始めかっこだけは全角で残し、折り返して行頭に来たかっこだけを詰めたいときは、space-first を使います。MDN では、段落の最初の行と、強制改行(<br> など)の直後の行で、行頭の始めかっこを全角にする値と説明されています。検証環境では、それ以外の行(自動で折り返した行)の行頭の始めかっこは半角になりました。

検証環境で、幅を5文字分にした段落に次の内容を入れ、3つの行の頭にある 「 の幅を測りました。

html
<p>「東京」<br>「大阪」と「名古屋」</p>

1行目は段落の最初、2行目は <br> の直後、3行目は自動で折り返した行です。

値 段落の最初 <br> の直後 自動の折り返し
normal(初期値) 1.00 1.00 1.00
space-all 1.00 1.00 1.00
space-first 1.00 1.00 0.50
trim-start 0.50 0.50 0.50
3つの段落を縦に並べた画面。左端に水色の線がある。上の「指定なし(初期値の normal)」は、3行とも行頭の「の左に半角ほどの空きがある。中の「text-spacing-trim: space-first」は、1行目と2行目の「の左に空きがあり、3行目の「いいえ」の「は左端の線に接している。下の「text-spacing-trim: trim-start」は、3行とも「が左端の線に接している
行頭の始めかっこの比較。上から初期値、space-first、trim-start。3行目は自動で折り返した行

text-spacing-trim は子要素に継承されます。検証環境でも、body に trim-start を指定すると、中の段落の行頭のかっこが半角になりました。サイト全体にまとめて効かせるなら、body に1回書けば足ります。

フォントに halt か chws の機能がないと効かない

かっこを半角にするには、フォントの中に半角の字形の情報が必要です。MDN には、フォントが OpenType の halt か chws の機能を持っていないと text-spacing-trim は無効になる、と書かれています。

検証環境の2つのフォントを、Python のライブラリ fontTools で調べると、Noto Sans CJK JP は halt を持ち、IPAゴシックはどちらも持っていませんでした。次のコードで、IPAゴシックのファイル(ipag.ttf)を調べると False False と出ます。

python
from fontTools.ttLib import TTFont

font = TTFont("ipag.ttf")
tags = set()
if "GPOS" in font:
    tags = {r.FeatureTag for r in font["GPOS"].table.FeatureList.FeatureRecord}
print("halt" in tags, "chws" in tags)

IPAゴシックで同じ文章を表示すると、初期値でも trim-start を指定しても、かっこと句読点はすべて全角の 1.00 のままでした。text-spacing-trim を書いても見た目が変わらないときは、表示に使われているフォントがこの機能を持っているかを確かめてください。

行末の句点は、詰めて行に収めてはくれなかった

仕様の normal は、行末の閉じかっこや句読点が行に入りきらないとき、半角にして収めることを許しています。

検証環境で、幅を9.5文字分にした段落に「東」を9つ、「。」、そのあとに「東」を4つ続けて入れました。「。」を半角にすれば9.5文字分で1行目に収まります。ところが、初期値、space-all、trim-start のどれでも、1行目は「東」8文字で終わりました。「。」は半角にならず、直前の「東」といっしょに2行目へ送られています。行末の句読点を行の外にぶら下げる hanging-punctuation という別のプロパティもありますが、互換性データでは Chrome と Edge は対応していません。

Chromium では、同じ文章を並べて比べると行頭の詰め方が揃ってしまう

値の違いを見比べるために、同じ文章の段落を1ページに並べて値だけを変えると、検証環境の Chromium 153 では正しく比べられませんでした。

1つ目の段落を normal、2つ目を trim-start にして、どちらにも「「東」「東」」を入れると、2つ目の行頭の「も全角の 1.00 になりました。順番を入れ替えると、今度は normal の段落の行頭の「が半角になりました。どちらも、ページの中で先に置いた段落の、行頭の詰め方が使われています。2つ目の段落の最後の字だけを「西」に変えると、どちらの段落も値どおりの幅になりました。

隣り合うかっこの詰め方は、同じ文章でも normal と space-all で正しく違いが出ました。この記事の画像は、値ごとに別のページを開いて撮り、あとから縦に並べています。

Chrome と Edge だけが対応している

互換性データでは、text-spacing-trim と4つの値(normal、space-all、space-first、trim-start)は、Chrome と Edge が 123、Android の Chrome が 123 から使えます。Firefox と Safari(iOS の Safari を含む)は対応していません。互換性データと MDN では、実験的な機能として扱われています。

仕様には trim-both、trim-all、auto などの値もありますが、MDN によると、どのブラウザーもまだ実装していません。

​Posted by 86