line-height を 1 に設定することと ellipsis を極力避ける理由
line-height を 1 に設定する手法は、テキストが1行のみの際によく見られる。レイアウトの調整を容易にし、上下の余白が意図した高さと合わなくなるのを防ぐため、特にコンテナの高さを固定しているボタンやタグなどで使われがちだ。
Web における line-height とは何か?
W3C には明確な定義がある:
All elements have a ‘line-height’ property that, in principle, gives the total height of a line of text. Space is added above and below the text of the line to arrive at that line height.
例えば行の高さを 1.5、フォントサイズを 16px に設定した場合、行の高さは 16px * 1.2 = 24px となり、24px - 16px = 8px を計算した後、その 8px を半分に分けて文字の上下に配分する。これは half-leading(ハーフ・リーディング)とも呼ばれる。以下の画像を参照してほしい:
灰色のブロックが行の高さであり、half-leading と呼ばれる部分だ。W3C で定義されている half-leading は一般的な組版・印刷の用語と混同されやすい。印刷組版における leading は通常、ベースライン(下図の赤い線)から次の行のベースラインまでの距離を指す。
なぜ 1 に設定するのを避けるべきなのか?
line-height を 1 に設定するのは簡単だが、この前提は「テキストは必ず1行に収まる」という思い込みの上に成り立っていると僕は考えている。
しかし実際にはそうとは限らない。画面が小さくてテキストが収まりきらない人もいれば、文字を大きく拡大して表示する設定にしている人もいる。また、ユーザーが入力したテキストが表示されるケースもある。こういった状況では、もともと1行を想定していたテキストが折り返される可能性があり、そこで line-height を 1 にしていると、文字同士が重なって詰まり、非常に読みづらくなってしまう。
もうひとつのケースは翻訳(多言語対応)だ。テキストによっては翻訳後に長くなることがあり、実装時に height を固定値で指定していると、かえってレイアウト崩れを引き起こし、2行になったテキストがコンテナの高さを突き抜けてしまうことがある。
text-overflow を ellipsis に設定する
1行であることを保証したいなら、text-overflow を追加してテキストがはみ出た際に … で省略すればいいじゃないか、と思う人もいるかもしれない。状況によってはそれも解決策のひとつだが、最近僕が痛感したのは、これは言語によって異なる問題を引き起こすということだ。
例えば、日本語は膠着語であり、文の形(肯定・否定など)は文末の語尾変化によって決まる。そのため、最も重要な情報が文末に来ることが多く、ellipsis を適用すると極めて重要な情報が切り捨てられてしまいやすい。
- 私はイケメンです
- 私はイケメンではありません
もしテキストがちょうど「で」のところで切り捨てられたら、次のようになってしまう:
- 私はイケメンで…
結局イケメンなのか、それともイケメンじゃないのか? 教えてほしい
解決策
最もシンプルな解決策は、テキストが1行に収まるという前提をできる限り最初から設けないことだ。UIを設計する際も、テキストが表現できるスペースをできるだけ広く確保する。もうひとつの方法は、行の高さをコンテナの高さの一部とし、height を直接固定値で指定するのではなく、テキストの行の高さに応じてコンテナの高さが決まるようにすることだ。
高さが合わなかったりレイアウトが崩れたりするから line-height を 1 にしてるんじゃないか!
確かに言うのは簡単だが、最も根本的な問題は、half-leading がコンテナの上下にも含まれてしまうことにある。しかし大半の場合、僕たちが保持したいのは文字と文字の間の half-leading だけなのだ。
CSSを利用して、half-leading による高さの変化を相殺することができる。CSSには非常に便利な 1lh という単位がある。比較的新しい単位ではあるが、すでにモダンブラウザでサポートされている。
疑似要素を使って、余分な部分をネガティブマージンで相殺する。計算式としては、(1em - 1lh) / 2 を使うことで half-leading の値を取得できる。
.btn {
...
line-height: 2;
&::before {
display: block;
content: "";
width: 0;
height: 0;
margin-top: calc((1em - 1lh) / 2);
}
&::after {
display: block;
content: "";
width: 0;
height: 0;
margin-bottom: calc((1em - 1lh) / 2);
}
}
効果はこのようになる。line-height が 2 であっても、上下の half-leading をうまく消し去ることができた!
もうひとつの方法は、現在まだ草案段階にある text-box-trim プロパティだ。現在は Safari Preview のみが対応しているが、その効果はまさに上下の half-leading を切り取ることにある。GitHub の画像がその効果をとても分かりやすく示している:

これなら、line-height による高さの問題に悩まされることもなくなる!各ブラウザベンダーでの実装を待つにはまだ時間がかかりそうだし、草案のままで立ち消える可能性すらあるものの、少なくとも期待は持てる。
結論
本記事では line-height や text-overflow の使い方について見つめ直してきたが、多くのケースにおいてこれらは実際便利であり、十分役立つものでもある。今回は別の視点・考え方を提示してみたので、読者にとって新たな気づきになれば幸いだ。
関連記事
- Three.js で僕の部屋を表現する 僕が React Three Fiber を使って実際の自分の部屋をブラウザ上に再現し、実世界のオブジェクトを目録に見立て、空間の記憶を通してここ数年の生活と仕事について語った話。
- フロントエンドで画像を扱う際に注意すべきこと Jake Archibaldの記事を起点に、現代のレスポンシブ画像の書き方を整理する。なぜwidth/heightを付ける必要があるのか、CSSのaspect-ratioはいつ使うべきか、AVIFとWebPの選び方、そしてpicture/source/srcsetを使ったモバイル向け画像の切り替えについて。
- CSS field-sizing — たった1行のCSSでフォーム要素を自動リサイズする かつてtextareaの自動高さ調整は、JavaScriptでscrollHeightを監視するしかなかった。しかしCSSのfield-sizing: contentなら、わずか1行で代替でき、textarea、input、selectに対応している。本記事では従来のやり方のペインポイントと、field-sizingの使い方をまとめる。
- リンクの下線をもっと見栄え良くする:text-underline-offset デフォルトでは下線と文字が近すぎて、このスタイルを好まないデザイナーもいるし、僕自身もあまり綺麗ではないと感じていた。