CSSのサイズ指定時の単位について、というか%について詳しく述べる
CSSのサイズ指定時の単位について、というか%について詳しく述べる
モチベーション
今、仕事でフロントエンドエンジニアをやっているけど、案外CSSが苦手な人が多い。CSSはスタイルシート言語なので他のプログラミング言語のパラダイムがまるで当てはまらないことが大きな理由の一つなのかなと思う。
特に細かい仕様を頭に入れていないと何やねんみたいな挙動することも多い。
僕はCSSの肝は以下の3点だと考えていて、それさえマスターすればあとはプロパティを死ぬ程覚えるだけでなんとでもなるんでは?と思っている。
- ボックスモデル
- レイヤー
- 単位
というわけでこの内の単位について、忘れないうちに記述しておこうと思う。
単位の種類
単位の種類は他にもあるだろうけど、主に以下の種類がある
- px
- em
- rem
- vw
- vh
- vmin
- vmax
- %
それ以外にも様々あるので、上記以外のものも含むざっくりとした説明は以下の記事を見たらわかる。
[CSS]長さの単位
というか、ちゃんと調べたいのであれば仕様書はこれです。
Distance Units: the <length> type
そういうわけで具体的に見ていく
px
言わずもがな。
pxはwebの世界では絶対値としての地位を確立していると思う。絶対値といえばこれ。最も多くのシーンで使われているわかりやすい単位。
そういうわけで特に説明はないです🥰
em
pxは絶対値だったけど、これ以降に出てくるものはすべて相対値になる。
相対値とは、何かの値をもとに決まる値のこと。emの場合はそのコンテキストのフォントサイズで値が決まる。
<div class="target"></div>
.target {
font-size: 20px
height: 2em; /* 40px */
}
使い所
コンテキストに完全に依存するので割と使いにくいイメージがあるけど、逆にいえばコンテキストに依存させたいようなときはいいかもしれない。
例えば、ブログなんかの文字は1行あたりざっくり40文字未満が読みやすいらしいので、そういうときは
.entry {
width: 40em;
}
のようにしておくと、勝手に(font-size * 40)px
を計算してくれる。それ以外にも最大で3行だけ表示したいときの高さなんかも以下のような感じで指定できる。
.block {
overflow: hidden;
line-height: 1.6;
height: calc(3em * 1.6) /* line-heightを掛けてやる */
}
-
box-sizing: border-box
の場合でpadding
を上下にとっている場合はそれも勘案してやる必要がある。
rem
root要素のfont-sizeを基準にした相対値。
root要素ってのはなにかというとhtmlのことです。
html {
font-size: 62.5%; /* フォントサイズはデフォで16pxなので16 * 0.625 = 10px */
}
body {
font-size: 1.4rem; /* 14px */
}
こんな感じでメインで使う場合はhtmlにfont-size: 62.5%;
として、10px基準で扱い、px
の代わりに扱うことが多い。
pxかremか
戦争がおきそうなテーマでもあるし、僕も一度この件でtwitterで争いがおきたことがあったけど、やっぱ用途としてはpxの代わりという感じ。
ブラウザの機能ではフォントのサイズを変更することができる。これを変更した時にブラウザはhtml要素のfont-sizeを変更するので、remで指定しておくことでその変更を各要素のサイズに反映することが可能になる(そのために上記の指定ではhtmlのfont-sizeは%指定がされている)。
または今後2000pxを大きく超える閲覧環境が出てくるような場合、そのサイズに応じてhtmlのfont-sizeを変更してやれば閲覧環境に合わせたサイズで対応することも可能になる。
ただ、フォントサイズの変更も今どき単純にzoom機能を使うのでは?という気もするので、どこまで考えるかは要件次第って気もするけども。
rem を指定する場合の注意点
上記の通り、remだとサイズが可変することがある。
つまりここはpx、ここはremみたいに混ざってると上記のようなときに可変する場所としない場所が出てわけわからんことになるので、基本的にはpxかremかは統一したほうがいい。(多くの場合emと%はどれとも共存できるとおもう)。
逆にpxだとサイズが可変しないことから、remを使用している場合でも可変してほしくないborder-width
なんかはpxを指定するとかはありだと思う。
vw, vh
viewportのwidth、またはheightをもとにした相対値。
100vw = 画面の横幅という感じ。1vwなら画面の横幅の1%の値。
使いどころ
これはちょいちょい使う。例えばファーストビューにheight: 80vh
みたいにしたりとか。
あとはスマホ時にすべてのサイズをvwで指定することによって、デバイスのサイズが変わっても全く同じ見た目にするみたいなこともできる。代理店案件とかだと、デバイスが変わることによって、文字の入り方が変わるの嫌がられるみたいな闇があるらしく、そういう時に使ってたみたいな地獄みたいな話も聴いたことある。(その場合はぶっちゃけviewportを固定値にしてやれば済む話だけど)
body {
font-size: 3.73333333vw /* 14 / 375 */
}
iframe内のvw, vhの値
iframe内の要素にvw, vhがあたっている場合は、iframeのサイズが基準になる。
そりゃそうかという感じだけど、stack overflowにそういう質問が上がっていた。
vhの問題点
vhは便利だけど、スマホのブラウザだとアドレスバーの表示非表示によって若干意図しない挙動になる場合がある。
The trick to viewport units on mobile
そういう場合はおとなしくJavaScriptに頼るのが話が早そう。
vmin, vmax
viewportの短い方、長い方の値を基準にした値ということらしい。
全然使ったことない。
%
%は非常にややこしい。というかこの記事は基本的に%を説明したくて書いているので、ようやく本番がきたなと言う気持ち。
それではやっていくぞ💪
そもそも%ってなんやねん
今までのものは明確な基準値のある相対値だった。それはたとえば、font-sizeだったりview-portだったり、ある値をもとに数値が決定されていたわけだけど、この%というものに関しては付与するプロパティや状態によって基準値が変わる。
整理した感じ4種類あるので順にみていく。
1. コンテキストの相対値としての%
font-sizeのパターン。当たるはずの値を基準に割合を決定する。
body {
font-size: 20px;
}
h1 {
font-size: 200%; /* 40px */
}
逆にfont-size以外思いつかん。
2. 親の表示領域の相対値パターン
- width
- height
-
- margin
-
- padding
width、heightに関してはそうかなという感じがすると思う。親の表示領域の中での割合が値になる。
ただ、marginとpaddingに関しては親の表示領域の中でもwidthのサイズを基準とした値になる。
.parent {
width: 600px;
}
.child {
margin-top: 100%; /* 600px */
}
この特性をうまく使うと画像の縦横比を固定することができる。
.fixRatio {
display: block;
width: 100%;
}
.fixRatio::before {
content: '';
display: block;
padding-top: 75%; /* 横幅に対して75%の高さ */
}
どっちかにbackground-imageなんかを指定したり、.fixRatio
にposition: relative
して中でimg要素をposition: absolute
したりして使う。
結構よく使うイディオム。
親レイヤーを基準にするパターン
position: absolute
のときの%のパターン。
このときは祖先で1番近縁のposition: relative
を持つ要素のボックスを基準に相対値が決まる。
(position: fixed
のときはhtml?なのかな?)
- top, left, right, bottom
- width
- height
自分のサイズに依存するパターン
transfrom
プロパティのtranslate
がこれ。
自分のサイズに依存する。
.block {
width: 600px;
height: 200px;
transform: translate(50%, 50%); /* x方向に300px, y方向に100px移動する */
}
この特徴を活かして、中央表示なんかによく使われる。
全然どうでもいいことだけど、例えば以下のようにしてblock要素を左右中央表示することも出来る。
.block {
margin-left: 50%;
transform: translate(50%, 50%);
}
まぁ、margin: auto
でいいんだけど。
%が使えないプロパティ
以下のやつは使うことができない。
- border-width
- box-shadowのカラー以外の値
- opacity
多分他にもありそう。
そういうわけで
単位と仲良くなりましたか?
これでCSSと戦っていきまっしょう💪
Discussion
“marginとpaddingに関しては親の表示領域の中でもwidthのサイズを基準とした値”
え、そうなんですね😳情報ありがとうございます
これややこしいですよね👀
わかりやすいのでMDN引用しますが、そうらしいです
僕も最初知ったとき、ちょっとびっくりしました🙄