cssのremを使うとメディアクエリがすごく簡単になることが判明
この記事では、cssのremを使ってフォントサイズや、マージン、パディングをまとめて切り替えるテクニックを紹介します。このサイトでもPCサイズとスマホサイズを切替えるときに使っているテクニックです。LESSなどを使わずにcssをすっきりとさせることができます。ウェブの上級者の方には大したことないテクニックですが、私のような初心者の方にはおすすめです。
個別にサイズ指定するのは大変
さて、このサイトではPCとスマホで表示サイズを変えるため、550pxをブレイクポイントにしてフォントサイズや要素間のマージン・パディングをメディアクエリで切替えています。もしあなたがPCで閲覧しているのであれば、ブラウザの幅を変えて文字サイズやマージンが切り替わる様子を確認してみてください。
一番最初にこのサイトのcssを作った時、私はpc用とスマホ用それぞれに対して、各要素のフォントサイズやマージンなどを設定していました。イメージでいうとこんな感じ(下図)。
550px超と、550px以下の場合でそれぞれ値を個別に設定し、メディアクエリに切替える方法です。サイトをレスポンシブにする場合に一番最初に思いつく方法ですね。これでもちゃんとレスポンシブになるから機能的には問題ありませんでした。
でも、この方法はpc用とスマホ用にそれぞれ値を設定しなければならないので、めちゃくちゃめんどくさいです。要素の数が少ないうちはいいのですが、要素が増えてくるとcssがとてもごちゃごちゃして分かりにくくなります。そして「やっぱり全体的に値を変えたいな」という場合には、値を一個一個直していく必要があり、メンテナンス性も悪いです。作業中にミスも起きやすいです。
そこで、レスポンシブでサイズを一括変更するのにもう少し良い方法はないものかと調べた結果、いくつか方法があることを知りました。
サイズをまとめて変える方法3つ
cssでサイズをまとめて変更する方法は大きく分けて3つです。
1.LESSなど
はじめに目にとまったのがこの方法。LESSなどのcssプリプロセッサを使えば、変数を使って値を制御できます。(ウェブの上級者の方は当たり前のように使っているでしょうが、、、)
「これだよー、これこれ。」そうはじめは思ったのですが、よく考えたら私には他に勉強中のプログラム言語が他にもたくさんあります(php、javascript、jQueryなど)。これ以上新しい文法を覚えるのは正直ツライ。ということで、いったんこの方法はパスしました。
もう少し私に時間と気持ちに余裕が出てきたらLESSにチャレンジしたいと思っています。
2. css変数
さらにググっているうちにcss変数とよばれるものがあると知りました。どうやらcssには変数を使う能力がもともと備わっているらしい。
「なんだ、あるじゃん。何でもっと早く言ってくれないのよ。」と、css変数を使ってこのサイトのcssを全部書き直しました。
その結果、ちゃんと狙った通りに表示されるし、レスポンシブの切替えもばっちり機能しました、、、IE以外はね。残念なことにIEでサイトを表示すると、css変数を使った箇所は全て表示が崩れてぐちゃぐちゃな状態。IEはcss変数に対応していないとその時に知りました。。。。
このサイトの訪問者割合はIEが10%ぐらい。割合としては少ないので、IEを切り捨てる覚悟でしばらく運用していましたが、やっぱり気持ち悪いです。せっかくこのサイトに来てくれたIEユーザーに、残念な状態のサイトを見せてがっかりされたくないなと。
そしてまた次の方法を探す旅へ。
3. rem
そしてようやくたどり着いたのが、この記事のタイトルにもあるremを使う方法です。
remのもともとの用途はドキュメントのルート、つまりhtmlタグそのもののフォントサイズを定義する単位です。例えば、1rem = 16pxと定義すればそのhtml文書のフォントサイズは16pxが基準となります。また、h1の見出しなどで、フォントサイズを倍の32pxにしたい場合には、h1タグのフォントサイズを2remと指定します。このように、remを使うとルートで決めた定義に対する相対値としてフォントサイズの指定ができるようになります。
そしてremの便利なところは、フォントサイズだけではなく、各種要素のサイズ指定にも使えるという点です。例えば、p要素のマージンを32pxにしたい場合にはp{padding:2rem;}
と指定すればよいわけです。
このremの特性を応用すれば、ルート要素のrem定義をメディアクエリで書き換えることで、remを使ってサイズを指定しているすべての要素にまとめてその新しい定義が反映されるということになります。これは便利な匂いがプンプンしますね。
でも実際に私がremを使ってサイズの一括変更を試みたところ、少しコツが必要だとわかりました。remでハマりそうな注意点とうまく使うためのコツを私の体験談を交えて以下で説明します。
remを使ったがなぜかレスポンシブしない
remについて書かれているいろいろなサイトを読むと、1rem = 10pxにすると直感的にわかりやすいと書いてあります。「なるほど確かにそのとおりだ」と思い、以下のようなcssにしてみました。
/* ↓PC(横幅550px超)の場合 */
html{
/* 1rem = 10pxと定義 */
font-size: 10px;
}
body{
/* 基本のフォントサイズは16px */
font-size: 1.6rem;
}
h1{
/* 見出しは大きめの30px、パディングを20px*/
font-size: 3rem;
padding: 2rem;
}
p{
/* pはマージントップ40px */
margin-top: 4rem;
}
/* ↓スマホ(横幅550px以下)の場合 */
@media screen and (max-width: 550px) {
html{
/* 1rem = 5pxと再定義 */
font-size: 5px;
}
body{
/* フォントサイズを少し小さく14pxに(5px * 2.8rem = 14px) */
font-size: 2.8rem;
}
h1{
/* 見出しのサイズを小さく20pxに(5px * 4rem = 20px) */
font-size: 4rem;
/* パディングはPCの半分の10pxにしますが、ここで何も指定しなくても5px * 2rem = 10pxに自動で再計算されるはず */
}
p{
/* マージントップはPCの半分の20pxにしますが、ここで何も指定しなくても、5px * 4rem = 20pxに自動で算出されるはず */
}
}
このcssでは、ブラウザの横幅が550px超の場合には1rem = 10pxと定義し、550px以下の場合は1rem = 5pxと再定義しています。こうすることで、PC用(550px超)にマージンとパディングを指定すれば、スマホ用(550以下)は半分のサイズに勝手に再計算されるはずです。
しかし、このcssをchromeで試しても「レスポンシブしない」のです。PCサイズでは意図通りのサイズで表示されますが、550px以下にしてもメディアクエリが全く効かず、サイズが変わらないのです。
ちゃんと仕様に沿っているはずなのになぜ!?いろいろググってみてもなかなかそれらしい情報が見つかりません。Chromeのデベロッパーツールを見てみると、なぜか550px以下の時に、1rem = 5pxとした定義箇所が無効扱いになっていました。なぜだ~!?
煮詰まった私は、やけくそで上記のcssの値をいろいろ変えてみました。するとなぜかときどきメディアクエリが機能することがあります。「およ!?」何か条件があるのかな?
いろいろパターンを変えて模索していった結果、1remの大きさは10px以上でないとChromeが値を無効としてしまうようでした。remはそもそも文字サイズの指定に使うものですから、Chromeはユーザビリティを重視して1remが10px未満の場合は無視するようです。賢い!(けどそういう独自処理をされると、私のような初心者には原因解明が困難になるのでツライ面もあります。)
ちゃんとレスポンシブするようにcssを修正
レスポンシブしない原因が分かったので、cssを以下のように修整しました。今度こそちゃんとレスポンシブするはず!
/* ↓PC(横幅550px超)の場合 */
html{
/* 1rem = 100pxと定義 */
font-size: 100px;
}
body{
/* 基本のフォントサイズは16px */
font-size: 0.16rem;
}
h1{
/* 見出しは大きめの30px、パディングを20px*/
font-size: 0.3rem;
padding: 0.2rem;
}
p{
/* pはマージントップ40px */
margin-top: 0.4rem;
}
/* ↓スマホ(横幅550px以下)の場合 */
@media screen and (max-width: 550px) {
html{
/* 1rem = 50pxと再定義 */
font-size: 50px;
}
body{
/* フォントサイズを少し小さく14pxに(50px * 0.28rem = 14px) */
font-size: 0.28rem;
}
h1{
/* 見出しのサイズを少し小さく20pxに(50px * 0.4rem = 20px) */
font-size: 0.4rem;
/* パディングはPCの半分の10pxにしますが、ここで何も指定しなくても50px * 0.2rem = 10pxに自動で再計算されるはず */
}
p{
/* マージントップはPCの半分の20pxにしますが、ここで何も指定しなくても、50px * 0.4rem = 20pxに自動で算出されるはず */
}
}
修正のポイントは、PCの場合は1rem = 100px、スマホの場合は1rem = 50pxのように、1remの値を最初のcssの10倍の値にしたことです。こうすることで、Chromeの「1remは10px以上」という条件もクリアできます。
そしていざChromeで動作をチェックすると、今度はちゃんと狙った通りにレスポンシブしました。念のため他のブラウザでもチェックします。FirefoxもOK!EdgeもOK!問題児のIEは、、、OK!いずれのブラウザも意図通りにレスポンシブしました。
よし、remが使いこなせるようになった。これでマージンやパディングをPCとスマホでわざわざ指定し直す必要がなくなります!
remをさらに合理的に使う
ようやくremが使いこなせるようになったので、今度はcssをもっと合理的に整理していきます。
前述のcssは、マージンやパディングはメディアクエリで値を再指定する必要がなくなり、かなりスマートです。しかしフォントサイズはPCとスマホで個別に値を設定していてあまり美しくありません。そこでフォントサイズもスマートに切替えられるようにします。
で、フォントサイズの箇所を書き直したのが下のcssです。
/* ↓PC(横幅550px超)の場合 */
html{
/* 1rem = 100pxと定義 */
font-size: 100px;
}
body{
/* 基本のフォントサイズは16px */
font-size: 0.16rem;
}
h1{
/* 見出しは大きめの30px、パディングを20px*/
font-size: 0.3rem;
padding: 0.2rem;
}
p{
/* pはマージントップ40px */
margin-top: 0.4rem;
}
/* ↓スマホ(横幅550px以下)の場合 */
@media screen and (max-width: 550px) {
html{
/* 1rem = 50pxと再定義 */
font-size: 50px;
}
body{
/* フォントサイズを少し小さく14pxに */
font-size : calc((0.16rem * 100 / 50) * 0.9)
}
h1{
/* 見出しのサイズを少し小さく27pxに */
font-size : calc((0.3rem * 100 / 50) * 0.66)
/* パディングはPCの半分の10pxにしますが、ここで何も指定しなくても50px * 0.2rem = 10pxに自動で再計算されるはず */
}
p{
/* マージントップはPCの半分の20pxにしますが、ここで何も指定しなくても、50px * 0.4rem = 20pxに自動で算出されるはず */
}
}
太字の部分、メディアクエリでfont-sizeの指定にcalcを使っているところがポイントです。
この箇所の意味は、PC用で指定していたフォントサイズ0.16remにPC用とスマホ用のrem定義の比率(100 / 50)を掛けることで、いったん元のフォントサイズ(16px)に戻します。その後に小さく表示したい割合(0.9)を掛けてることでフォントサイズを14pxにしています。h1のフォントサイズも同じ考え方で指定しています。
このようにフォントサイズを指定するのは、一見まわりくどく見えます。しかし後々cssを見たときに「これはスマホではPC用のフォントサイズの0.9掛けにしたいんだな」という設定意図を把握しやすい利点があります。また、フォントサイズを指定する要素が増えてきても、とりあえず元の値の0.9掛けを指定しておけば、文字サイズのバランスを保ったまま全体的に縮小することができます。
もう一つ、このcssで強調したいポイントは、メディアクエリ内ではmarginやpaddingを一切指定する必要がないことです。メディアクエリで1rem = 50pxと再定義しているので、マージンやパディングはその再定義を元に自動計算されてサイズがPCの時の半分になるというわけです。わざわざスマホ用にマージンやパディングを指定し直す必要がありません。
まとめ
このサイトは、上記で説明した方法でcssを構築したおかげで、PC/スマホのレスポンシブ対応をかなり簡潔にすることができました。ほかにも使い方次第でいろいろ応用できると思います。ご自身でサイトやブログを作られている方は一度お試しください。
改めて読み返したらすごくダラダラの文章でした、、、ごめんなさい。でもこのテクニックは本当に使えますよ。
20年ぶりくらいに、ぽちぽちとHPを作り始めています。
スマホの文字の大きさ対応、とても分かりやすく凄く参考になりました!
ありがとうございます!!
ももんがさんへ
コメントありがとうございます。
ひさしぶりにHP作りするとわくわくしますよね。記事がお役に立てたならよかったです。
奇しくも、ももんがさんと同じように20年越しでウェブ関連業務を再起動した定年過ぎた高齢者です。(笑)
以前はレスポンシブデザインなど存在もしていませんでしたので、メディアクエリーの単位をremで指定する方法を探っていて寄り道させていただきました。emとremの使い分けが理解できたような感じです。ありがとうございました。
(回りくどくもなく分かりやすかったです)
まっさんん?さんへ
コメントありがとうございます。20年越しにウェブ再起動とはロマンがありますね!まっさんん?さんが20年ぶりにどんなことをウェブに書き記すのか興味があります。まっさんん?さんの今後のウェブライフが良きものとなりますよう!