[CSS]テキスト要素の先頭行だけline-heightを取り除き、上ぴったりに揃えるスタイルシートのテクニック
Post on:2018年8月21日
テキスト要素を配置する際、line-heightがあると、テキストの先頭行を上ぴったりに揃えることはできません。先頭行だけline-heightでできた上スペースを取り除き、上に揃えるスタイルシートのテクニックを紹介します。
これをしたいと思った人は少なくないと思います。
先頭行の余計な余白を取り除き、ぴたっと揃えることができます。取り除くのは先頭行の上だけなので、先頭行の下やほかのテキスト要素はline-heightが適用されます。
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
元々は、近日公開予定の「Web Components」のために作成したものですが、グローバルのCSSとして利用できるので、一足先に公開します。
先頭行だけを上に揃えるスタイルシート
先頭行だけを上に揃えるには、テキストのブロックからline-heightで加えられた上部のスペースだけを取り除けば実現できます。
説明は後述します。
1 2 3 4 5 6 7 8 9 |
@mixin lhCrop($line-height) { &::before { content: ''; display: block; height: 0; width: 0; margin-top: calc((1 - #{$line-height}) * 0.5em); } } |
適用するテキスト要素に上記を含め、Mixinの引数としてline-heightの値を渡します。
1 2 3 |
.text-to-crop { @include lhCrop(1.2); //line-height: 1.2 } |
ライブラリ用に構築したフレームワークでは、line-heightの値はCSS変数で扱っています。つまり、CSS変数を使用してMixinのlhCropを呼び出すことができます。
1 2 3 4 5 6 7 8 9 10 |
:root { /* line-height */ --heading-line-height: 1.2; --body-line-height: 1.4; --article-line-height: 1.58; } .text-to-crop { @include lhCrop(var(--heading-line-height)); } |
こうすることのメリットの1つは、CSS変数の値を変更する(Mixinで呼び出しを変更する必要がない)場合や、line-heightの変数が異なるMedia Queriesで変更された場合、トリミングされる値が自動的に更新されることです。Mixinを再利用する必要はありません。
テクニックの解説
このMixinを使用すると、::before疑似要素に負のマージンで作成され、テキスト要素の上のスペースが取り除かれます。
負のマージンで擬似要素を使用するというアイデアは、Kevin Powellによって初めて紹介されました。参考: Cropping Away Negative Impacts of Line Height
その仕組みを見てましょう。
- テキスト要素の全高(文字の高さ+上スペース+下スペース)は、line-heightにfont-sizeを掛けたものに等しくなります。
- 文字の高さはfont-sizeと等しい(近似値)と仮定します。
グリーン: font-size、オレンジ: font-sizeとline-height、ブラック: 上スペース
全体の値に、上と下のスペースが含まれていることが分かります。
1 |
total-space = font-size*line-height - font-size = (line-height - 1)*font-size = (line-height - 1)*1em |
font-sizeを1emにしているのは、::before擬似要素で適用される要素のfont-sizeを等しくするためです。
上と下のスペースが等しいとすると、下記のようになります。
1 |
top-space = (line-height - 1)*1em/2 = (line-height - 1)*0.5em |
このtop-spaceの値は、Mixinで使用される値のベースになります(上スペースを取り除くには負のマージンが必要です)。下スペースにも同様のMixinを作成することができますが、現状これは必要ではないでしょう。
免責事項
lhCrop Mixinは2つのルールに基づいています。
- 文字の高さはfont-sizeに等しい。これはあくまで近似値です。
- 文字の上スペースは、下スペースと同じ。これは通常正しくありません。
このルールは、使用するフォントによって異なります。例えばRobotoの文字の高さだと、font-sizeの75%になります。使用するフォントに合わせて、値をカスタマイズして利用してください。
例えば、文字の高さを変更する場合、Robotoを例にカスタマイズしてみます。Robotoは75%なので、1*font-sizeではなく0.75*font-sizeにすると、上マージンの値は下記のようになります。
1 |
margin-top: (0.75 - line-height)*0.5em |
この変数を考慮したMixinは、下記のようになります。
1 2 3 4 5 6 7 8 9 |
@mixin lhCrop($line-height, $capital-letter: 1) { &::before { content: ''; display: block; height: 0; width: 0; margin-top: calc((#{$capital-letter} - #{$line-height}) * 0.5em); } } |
これはMixinに2番目の値を渡すことができます。デフォルトでは、この値は1です(文字の高さがfont-sizeに等しい)。しかし、調整が必要な場合は別の値を使用できます。
1 2 3 |
.text-to-crop { @include lhCrop(1.2, 0.75); //using Roboto font family } |
この変更されたバージョンのMixinを使用する場合は、_typography.scssファイルに各フォントの文字の変数を定義し、lhCrop Mixinを呼び出すときにその変数を使用することをお勧めします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
:root { /* line-height */ --heading-line-height: 1.2; --body-line-height: 1.4; --article-line-height: 1.58; /* capital letters - used in combo with the lhCrop mixin */ --font-primary-capital-letter: 0.75; --font-secondary-capital-letter: 0.69; } .text-to-crop { @include lhCrop(var(--body-line-height), var(--font-primary-capital-letter)); } |
これにより、あなたのシステムを非常に簡単に保つことができます。フォントファミリを変更する場合は、Mixinを修正する必要がなく、文字の変数を更新するだけです。
下記のデモで、実際の動作を確認できます。
See the Pen Line-height Crop by Claudia (@claudiar) on CodePen.
値を調整すると、日本語にも利用できます。
日本語の先頭行だけを上に揃える
2番目の上と下のスペースが同じは、使用しているフォントファミリのディセンダ(下スペース)とアセンダ(上スペース+文字)を考慮する必要があります。しかし、これは使用する必要性がないため、カスタマイズ版は作成していません。
もしピクセル単位での完璧な精度を必要とするなら、「Text Crop」を使用するのが良い解決方法です。
参考: 文字に含まれる上下の余白を取り除いて、アイコンや画像とぴったり同じ高さにするスタイルシート
今のところ、Mixinの簡略化されたバージョン(2番目の$capital-letterは含まれていない)を使用することに決めました。これまでのところすべての実験で十分正確であることが判明しました。
sponsors