【css】remを使ってfont-size、margin、paddingをまとめて切り替えるテクニック。メディアクエリで活用

この記事では、cssのremを使ってフォントサイズや、マージン、パディングをまとめて切り替えるテクニックを紹介します。このサイトでもPCサイズとスマホサイズを切替えるときに使っているテクニックです。LESSなどを使わずにcssをすっきりとさせることができます。ウェブの上級者の方には大したことないテクニックですが、私のような初心者の方にはおすすめです。

PC、スマホで個別にサイズを指定するのがめんどくさい

さて、このサイトではPCとスマホで表示サイズを変えるため、550pxをブレイクポイントにしてフォントサイズや要素間のマージン・パディングをメディアクエリで切替えています。もしあなたがPCで閲覧しているのであれば、ブラウザの幅を変えて文字サイズやマージンが切り替わる様子を確認してみてください。

一番最初にこのサイトのcssを作った時、私はpc用とスマホ用それぞれに対して、各要素のフォントサイズやマージンなどを設定していました。イメージでいうとこんな感じ(下図)。

もともとのやり方

550px超と、550px以下の場合でそれぞれ値を個別に設定し、メディアクエリに切替える方法です。サイトをレスポンシブにする場合に一番最初に思いつく方法ですね。これでもちゃんとレスポンシブになるから機能的には問題ありませんでした。

でも、この方法はpc用とスマホ用にそれぞれ値を設定しなければならないので、めちゃくちゃめんどくさいです。要素の数が少ないうちはいいのですが、要素が増えてくるとcssがとてもごちゃごちゃして分かりにくくなります。そして「やっぱり全体的に値を変えたいな」という場合には、値を一個一個直していく必要があり、メンテナンス性も悪いです。作業中にミスも起きやすいです。

そこで、レスポンシブでサイズを一括変更するのにもう少し良い方法はないものかと調べた結果、いくつか方法があることを知りました。

サイズをまとめて変えるにはこんな方法がある

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にしたい場合には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の値をいろいろ変えてみました。するとなぜか値によってはChromeが反応する場合があります。「およ!?」何か条件があるのかな?

いろいろパターンを変えて模索していった結果、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の時の半分になるというわけです。わざわざスマホ用にマージンやパディングを指定し直す必要がありません。

記事ID:838

この記事へのコメント

コメントをどうぞ

関連記事