CSSでテキストの上下にできる余分なスペースを解消する方法
CSSのtext-box-trimで文字の上下にある余白を調整。フォントメトリクスとline-heightが隙間を生む仕組み、text-box-edgeの選び方、旧ブラウザー向けの代替策を解説します。
テキストの上下にできる余分なスペースには、2つの原因があります。1つはフォントに組み込まれた垂直方向のメトリクス、もう1つは line-height が行の上下それぞれに追加(または削除)するハーフレディングです。CSSネイティブの解決策は text-box: trim-both cap alphabetic です。
line-height: 1.1 を設定し、マージンもすべて取り除いたのに、見出しは文字よりも背の高いボックスに収まったままです。そこでネガティブマージンを追加し、見た目が整うまで値を調整して、ひとまず作業を終えます。ところがその後、ブランドフォントが変更されます。
本記事では、このスペースがどこから生じるのか、ネガティブマージンではなぜ確実に除去できないのか、そして text-box-trim、text-box-edge、text-box ショートハンドを使って見出しやボタンのスペースをトリミングする方法を解説します。最後に、古いブラウザ向けのフォールバックも紹介します。
重要なポイント
- テキスト周囲の余分なスペースは、フォントが最も背の高いグリフや最も深く下がるグリフのために確保している垂直方向の領域と、
line-heightによって追加または削除されるレディングから生じます。CSSはこのレディングを各行の上下に均等に配分します。 text-box-trimはトリミングする端(none、trim-start、trim-end、trim-both)を指定し、text-box-edgeは各端をどのラインまでトリミングするかを指定します。text-box: trim-both cap alphabeticは、上端をキャップハイトまで、下端をベースラインまでトリミングします。これは多くのデザインにおけるスペースの測り方と一致します。text-box-edgeは、text-box-trimにnone以外の値が設定されていない限り効果がありません。text-box-trimは継承されないため、bodyではなく、トリミングしたい各要素に宣言する必要があります。
症状:パディングでは説明できない隙間
パディングもマージンもゼロにし、line-height を詰めているにもかかわらず、見出しの大文字の上とベースラインの下に空白が残ります。DevToolsで確認すると、コンテンツボックスは表示されている文字よりも背が高く、その差を説明するものはスタイルシートのどこにも見当たりません。
よくある対処法は、試行錯誤で見つけたネガティブマージンを当てることです。
h1 {
line-height: 1.1;
/* Tuned by eye for one font; wrong for any other */
margin-block: -0.2em -0.15em;
}
これらの値は説明用のプレースホルダーです。何らかの根拠から導き出されたものではなく、まさにそこが問題なのです。
なぜテキストの上下に余分なスペースができるのか
テキストの上下の余分なスペースには、フォントメトリクスとハーフレディングという2つの原因があり、どちらもボックスモデルではなくテキスト側に属するものです。
第一に、フォントは背の高い大文字から g や y のような文字の下に伸びる部分まで、すべてのグリフのために垂直方向の領域を確保しています。MDNの text-box-trim リファレンスにもあるとおり、確保される領域の大きさは書体ごとに異なります。そのため、同じ font-size でもフォントによってラインボックスの高さが変わります。
第二に、line-height はレディングを追加します。CSS 2.1仕様のレディングとハーフレディングに関する項では、レディングを line-height とフォントのアセントおよびディセントの合計との差として定義しています。その半分がグリフの上に、残りの半分が下に配置されます。多くのフォントではアセントとディセントの合計が1.1emを超えるため、line-height: 1.1 ではハーフレディングが小さくなるか、マイナスになることも珍しくありません。いずれにしても、フォント自体のメトリクスによって大文字の上とベースラインの下に生じる空白はそのまま残ります。
書体ごとに確保される垂直方向のスペースは異なるため、あるフォントに合わせて調整したネガティブマージンは、別のフォントでは正しく機能しません。これにはWebフォントが読み込まれる前に表示されるフォールバックフォントも含まれ、この問題はフォントに起因するレイアウトシフトの原因にもなります。Webフォントの読み込みが遅れたセッションをリプレイすると、フォントが切り替わり、マジックナンバーのマージンを使った見出しがずれるフレームを確認できます。
text-box-trimで隙間を解消するには
text-box-trim はテキストブロックのどの端をトリミングするかを指定し、text-box-edge は各端をどのラインまでトリミングするかを指定します。text-box-trim は次の4つのキーワードを受け付けます。
none:初期値。何もトリミングしません。trim-start:オーバー(上)端をトリミングします。trim-end:アンダー(下)端をトリミングします。trim-both:両端をトリミングします。
先ほどの見出しのマージンハックを置き換えると、次のようになります。
h1 {
line-height: 1.1;
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}
text-box-trim を適用すると、ボックスの上端は大文字の上端に、下端はベースラインに揃います。ブラウザが推測値ではなくフォントから位置を読み取るため、どのフォントでも余分なスペースがなくなります。
text-box ショートハンドを使うと、両方のプロパティを1つの宣言にまとめられます。次の2つのルールは同等です。
h1 {
text-box: trim-both cap alphabetic;
}
/* Same result: an omitted trim keyword means trim-both */
h1 {
text-box: cap alphabetic;
}
重要な text-box-edge の値
横書きテキストの場合、cap alphabetic と ex alphabetic の2つの組み合わせでほぼすべてのケースに対応できます。text-box-edge は2つのキーワードを取り、1つ目がオーバー端を、2つ目がアンダー端を指定します。
| キーワード | 端 | トリミング先 |
|---|---|---|
text | オーバーまたはアンダー | フォントのテキストエッジ(デフォルトの auto はこの値に解決されます) |
cap | オーバーのみ | 大文字の上端 |
ex | オーバーのみ | エックスハイト(背の低い小文字の上端) |
alphabetic | アンダーのみ | アルファベティックベースライン |
cap alphabetic は、デザイナーが見出しやラベル周りのスペースを測る一般的な方法、つまりキャップハイトからベースラインまでという測り方と一致します。テキストの大部分が小文字で、エックスハイトが視覚的な上端になる場合は ex alphabetic を使用します。
.lowercase-label {
text-box: trim-both ex alphabetic;
}
多くの人がつまずく3つのルールがあります。
text-box-edgeは単独では効果がありません。text-box-trimにnone以外の値が設定されていない限り、何もトリミングされません。text-boxショートハンドでは、トリミングのキーワードを省略するとtrim-bothに、エッジを省略するとautoになります。キーワードnormalはnone autoと同等です。text-box-trimとtext-box-edgeはどちらも継承されません。bodyに設定しても、その中の見出しやボタンはトリミングされません。各要素、または各コンポーネントのベーススタイルで宣言してください。
text-box でボタンラベルを中央に配置する
上下のパディングが等しいボタンでも、ラベルが中央からずれて見えることがよくあります。パディングは等しくても、大文字の上とベースラインの下にあるフォント内部のスペースは等しくないため、その差が片側の余分なパディングとして見えてしまうのです。
.button {
padding: 0.75rem 1.25rem;
}
ラベルのボックスをキャップハイトとベースラインまでトリミングすると、テキストとボタンの端の間にあるスペースはパディングだけになります。
.button--trimmed {
padding: 0.75rem 1.25rem;
text-box: trim-both cap alphabetic;
}
「Submit」のようなラベルでは、大文字の上のスペースとベースラインの下のスペースが同じように見えるようになります。CSS Inline Layout仕様では、text-box-trim をブロックコンテナ、マルチカラムコンテナ、インラインボックスに適用できると定めていますが、ブラウザによって挙動は異なります。Mozillaのintent to shipによると、FirefoxとSafariはインラインボックスをトリミングしますが、Chromiumはトリミングしません。また、フレックスコンテナやグリッドコンテナに対してはトリミングの効果がないため、ボタンに display: inline-block を指定するか、ボタン内のラベル要素にトリミングを適用してください。下端がベースラインまでトリミングされるため、g、p、y などの文字のディセンダーはパディング領域にはみ出します。これはタイポグラフィとして想定どおりの結果であり、バグではありません。
ブラウザサポートとフォールバック
MDNでは text-box を Baseline 2026(2026年8月より新たに利用可能)としており、古いデバイスやブラウザでは動作しない可能性があると注記しています。サポートしていないブラウザはこの宣言を無視し、通常のフォントスペーシングでテキストをレンダリングします。フォールバックはトリミングされていないレイアウトであり、表示が崩れるわけではなく、精度が下がるだけです。デザインが従来の補正用マージンに依存している場合は、@supports 機能クエリを使って、それらのブラウザに対してのみマージンを残しておきましょう。
h1 {
text-box: trim-both cap alphabetic;
}
@supports not (text-box: trim-both cap alphabetic) {
h1 {
/* Old per-font patch, kept only where text-box is unsupported */
margin-block: -0.2em -0.15em;
}
}
まとめ
テキスト周囲の隙間は、フォントメトリクスとハーフレディングによるものです。ネガティブマージンはそれを隠すだけで、しかも1つの書体にしか通用しません。各見出しやラベルのコンポーネントでは、そうしたマージンを text-box: trim-both cap alphabetic に置き換え、従来のマージンは @supports not の中に移し、Webフォントだけでなくフォールバックフォントでも結果を確認してください。
よくある質問
text-box-trimは複数行の段落における行間を変更しますか?
いいえ。ブロックコンテナに対して、text-box-trimが影響するのは最初の行の上端と最後の行の下端のみです。折り返された行の間のハーフレディングはそのまま維持されるため、段落内の行間は引き続きline-heightで制御されます。キャップハイトとベースラインまで内側に移動するのは、ブロックの外側の端だけです。
余分なスペースをなくすために、単にline-height: 1を設定すればよいのでは?
line-height: 1を設定しても、変わるのはレディングだけです。大文字の上とベースラインの下にフォント自体が確保しているスペースは残るため、ボックスの端はキャップハイトやベースラインと揃いません。さらに、折り返された行同士の間隔も詰まってしまいます。text-box-trimは外側の端だけをフォントメトリクスに合わせてトリミングするため、可読性の調整はline-heightに任せることができます。
text-boxによるトリミングは周囲の要素のレイアウトに影響しますか?
はい。text-box-trimは要素のコンテンツの端を指定したメトリクスまで内側に移動させるため、要素が占めるブロック方向のスペースが小さくなります。マージン、フレックスやグリッドのギャップ、隣接する要素は、フォントが確保しているスペースではなく、トリミング後の端から測られるようになります。そのため、トリミングを適用するとスペーシングトークンが視覚的に正確になり、従来のネガティブマージンを削除することが重要になるのです。
JavaScriptでtext-boxのサポートを検出するには?
CSS.supports('text-box', 'trim-both cap alphabetic') を呼び出します。この宣言を受け付けるブラウザではtrueを、受け付けないブラウザではfalseを返します。CSSの@supportsルールと同じテストを実行するため、補正用マージンを適用するかどうかを実行時に判断したり、ユーザーがどのレンダリングパスを利用しているかをログに記録したりするのに使えます。
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Star on GitHub12k