rem単位を用いたレスポンシブ対応ページの実装デモ
はじめに
本技術のポイントは1つだけです。可変にしたい要素すべてのサイズ指定にrem単位を用いることにより、普通にやると面倒なレスポンシブ対応がfont-sizeのみの変更で済むことです。
このサイトがデモです。
(ウィンドウ幅を狭くしたり右上のチェックボックスを切り替えてみてください。)
きっかけ
ごろにAppleサイトのサポートページ(https://support.apple.com/ja-jp/HT...)を開いたところ、大きな表示崩れが生じていました。
CSSを解読したところ、要素のところどころにrem単位を用いたサイズ指定が施されていました。
これは単なる凡ミスではないと考えた私は、バグの原因(後述)を回避した上で、remを用いることでメリットがあるのではないかと思い、本記事を執筆しました。
rem単位とは
CSSには元来emや%といった「親要素の文字サイズ」に対して相対的にサイズ指定をする単位がありました。一方、絶対的なサイズ指定をするpxもよく使われています。そんな中、remという新しい単位がCSS3で導入されました。HTML要素(ルート)に指定されたフォントサイズが1remに相当します(remはroot emの略)。
参考: CSS3の新単位remで、文字サイズの指定を分かりやすく [ホームページ作成] All About
参考: CSS Units(英語)
バグの原因
Appleサイトでは、1remにあたるフォントサイズとして1pxが指定されていました。
html {
font-size:1px
}
該当CSSファイル(※現在はremに関する記述なし)
これにより、たとえば50remは50pxとして扱われるはずです。
たしかにFirefoxやInternet Explorerなどではその通りなのですが、Chromeではそうならないというのがポイントです(Safariも、設定によっては崩れます)。
Chromeの最小フォントサイズ問題
Chromeには、最小フォントサイズというブラウザー設定が存在し、デフォルトで10pxに指定されています。
ブラウザーの設定により、最小フォントサイズを下げることはできますが、それでも最低6pxまでしか下げられません。
よって、html要素のフォントサイズに1pxを指定しても、デフォルトのChromeでは1rem = 10pxと扱われてしまうのです。(ただし見た感じだとfont-sizeだけは1rem = 1pxとして扱われる模様)
なお、htmlのフォントサイズを10px以上で指定しながらremで指定したサイズが10pxを下回る場合(1rem = 10px, 0.5rem→5pxなど)は、テキスト以外なら有効のようです。
1rem = 1pxということになるので、なぜAppleはpxを使わずremを使ったのかが謎です(後述のズームコントロールを視野に入れていたのでしょうかね?)。
提案: remハック
remをハックして何か便利なことがないかと考えた結果、最も有用なのは拡大を伴うレイアウトで、特にPC・スマホのレイアウト切替時のサイズ変更に役立つと閃きました。
レスポンシブ対応
HTMLが単一ソースで、画面サイズに応じてレイアウトが切り替わる技術のことをレスポンシブWebデザインと呼びます。
従来法
JavaScriptによるCSS操作
リサイズに応じてwidth・heightなどのCSSプロパティを書き換える手法です。
ただし、工数がかかるためかあまり見かけません。
zoomプロパティ
要素の拡大率を変更してコンテンツサイズを変化させられます。
Firefoxでzoomプロパティが実装されていないのが最大の欠点です。
CSS transform
要素全体を拡大縮小する方法です。(以下は例)
.wrapper {
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
全体を縮小することにより手っ取り早くレスポンシブにできますが、いいね!ボタン等のiframe要素なども同時に縮小されてしまいます。
この方法だと、また、DOM要素の大きさに影響を与えないため、レイアウトに不具合が生じる欠点もあります。
メディアクエリによるCSS
レスポンシブ対応としては最も適した方法です。
しかし、それなりに工数がかかるのが難点です。
提案法
ウィンドウ幅にフィット
コンテンツ幅320px、ルート単位10pxの場合、画面にフィットさせる場合は以下のように指定するとフィットできます。
本ページの右上にある「ウィンドウ幅にフィット」をチェックした際の動作です。
ただし、windowのwidthを元にremサイズを反映させる実装をすると、ウィンドウのズームが一定率無効になる挙動を確認しております。
html {
font-size: calc(100vw / 320 * 10);
}
calcが安心できない場合は数値で3.13vw
としましょう。
なお、vwはスクロールバーを考慮しないようで、対応ブラウザーもまだ少ないため、今のところCSSを使わずJavaScriptでリサイズのイベントに従って動的に変更し、フォールバックとしてvwを使うことをお勧めします(実装方法は js/fit-window.js を参照)。
表示サイズの2段階切り替え
また、PCで640px幅、スマホで320px幅というようなレイアウトに対しても本手法は有用です。以下のようにメディアクエリを使えば表示サイズを切り替えられます。
html {
font-size: 20px;
}
@media screen and (max-width: 640px) {
html {
font-size: 10px;
}
}
「PCレイアウトでの100pxが5rem、スマホレイアウトでの100pxが10rem」のように、若干混乱する計算とはなってしまいます。共同プロジェクトで扱う場合は注意しましょう。
Sass等を利用できる環境の場合、ピクセルをremに換算する関数を用意してもよいかもしれません。
ちなみに、Sassを利用することで、rem単位からピクセル単位へのフォールバックも自動で行われるため、IE8で表示が崩れないようになるという利点もあります。
ソース
※一部ソースは本筋と関係ないので割愛
対応状況
IE8 | IE9, IE10 | IE11 | Safari | Chrome | Firefox | Android 標準ブラウザー |
iOS Safari |
---|---|---|---|---|---|---|---|
× | ○※ | ○ | ○ | ○ | ○ | ○ | ○ |
※IE9, IE10ではfontプロパティーのショートハンド表記やline-heightプロパティーに不具合があるそうです。
出典: Can I use...
参考: IE10/11 のバグを考えると CSS では rem 単位を使わない方が良い | かきしちカンパニー Web Magazine
その他の応用
ズームコントロールへの応用ができそうです。
CSS-Tricksのこちらの記事では、remとemを併用してグローバル・ローカルな領域でブロックサイズ制御をするデモが公開されています。
ズームコントロールの各種比較の簡単なデモはこちらになります。
まとめ
rem単位を用いることで、なんちゃってレスポンシブページを非常に簡単に作ることができます。
Chromeの最小フォントサイズがネックですが、フォントサイズ以外のプロパティーにもremを指定できることがかなり強力です。
参考: CSSの基本単位としてremを使うと超絶便利 - Qiita(筆者の記事)