CSSでメディアクエリはもう必要ないかも -メディアクエリなしで実装するテクニックのまとめ
Post on:2021年11月18日
Webサイトやアプリをレスポンシブ化するためにメディアクエリに頼っているのであれば、CSSの機能を見直して、昔ながらのブレークポイントを新しい流動的なアプローチで実装ができないか検討する時期かもしれません。
CSSの実装はデバイスベースからコンテンツベースに移行しているのが現状です。grid
, flexbox
, vh
, vw
, calc
, clamp
, min
, max
など、CSSの機能を使用してレスポンシブ対応にするテクニックを紹介します。
You Probably Don't Need Media Queries Anymore
by Kathryn Grayson Nanz
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
古き良き時代のWeb制作ではレスポンシブなWebサイトやアプリを制作する場合、特定のデバイスのブレークポイントに基づいてメディアクエリを定義し、それぞれのサイズに合わせてコンテンツを作り直すことを意味しました(本当の昔はテーブルレイアウトだったとコメントでありますが、私もそれを覚えていますし、最悪でした)。
そして、デバイスのブレークポイントを容易にするために、Bootstrap、SkeletonなどのCSSフレームワークが登場しました。ブレークポイントをすべて記述するのは大変な作業だったからです。
さまざまな大きさや形のデバイスが登場するにつれ、メディアクエリの定義に関するベストプラクティスはデバイスベースからコンテンツベースに移行しているのが現状です。ブレークポイントの時代は終わり、フルード(流動的)デザインの時代が到来したのです。
あるポイントに到達すると新しいレイアウトに切り替わるのではなく、コンテンツは常に利用可能なスペースの量に基づいて最適化される必要があります。
ありがたいことに、CSSも大きく進化しました。多くのデベロッパーはレスポンシブ対応のためにメディアクエリを1つまたは複数定義することに慣れてしまい、その習慣が抜け出せないままになっています。しかし、grid
, flexbox
, vh
, vw
, calc
, clamp
, min
, max
, aspect-ratio
などのCSSがある現在、メディアクエリに頼る必要はありません。
この記事では、大局的なレイアウトから小粒の単位にいたるまで順を追って解説したいと思います。古いスタイルシートはリファクタリングが可能です。わたし達はそれらのテクニックを使用できます!
大局的なgridとflexbox
まずは、最もポピュラーなレスポンシブの表示に使用するgrid
とflexbox
から始めます。grid
は2017年に、flexbox
は2013年にブラウザで完全にサポートされるようになりました。この2つの違い、どちらか1つ(または2つとも)を使用する必要があるのかきちんと理解しておく必要があります。誤った同等性を想定している人もいますが、実際にはこの2つは使用例は大きく異なるだけでなく、お互いに補完するために一緒に使用することもできます(そうすべきです)。
参考:
- CSS Gridが適しているレイアウト、Flexboxが適してるレイアウトを詳しく解説
- FlexboxとCSS Gridの使い分け方、よく見かけるUIコンポーネントをFlexboxとGridで実装するテクニックのまとめ
この記事では、メディアクエリを使用せずに、レスポンシブの調整や自然な折り返しを可能にする方法でページ上の要素のレイアウトを処理する方法にフォーカスします。
Grid
grid
は複数の行と列を持つグリッドを作成し、そこに要素を配置することを主な目的としています。ラッパーとなるグリッドコンテナを作成し、その中に子要素を配置します。グリッドの行、列、セルはさまざまななカスタマイズが可能で、シンプルなグリッドから複雑なグリッドまで作成できます。
参考:
シンプルでレスポンシブなデザインを目指しているわたし達にとって、最も重要な機能を見てみましょう。grid
は列や行を自動的に繰り返す機能(repeat()
)、利用可能なスペースに列のサイズを自動的に調整する機能(auto-fit
)があります。例えば、以下のようなコードです。
1 2 3 4 5 6 7 8 9 10 11 12 |
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } -------- <div class="grid"> <div></div> <div></div> <div></div> </div> |
このCSSではグリッドはコンテンツをスペースに収まるカラムに変換し、各カラムの最小幅を300px
以上、最大幅を1fr
以下に設定しています。1fr
は分数を意味するCSSの単位で、スペースを均等に分割し、各カラムにそのスペースの分数を分配するようにブラウザに伝えます。この場合では、3つの均等なカラムを作成し、それぞれが利用可能なスペースの1/3を占めますが、300pxより小さくなることはありません。さらにdiv
を追加したり削除すると、grid
は自動的に計算して表示を調整します。また、スクリーンが小さすぎてカラムを横一列に配置できない場合は、残りのカラムを自動的に次の行に折り返します。
grid
を使用してより複雑なレイアウトを作成したい場合は、以下のリソースをご覧ください。
- A Complete Guide to Gridは、さまざまな幅のカラムの作成、
template-areas
の定義、グリッドセル間のgap
の定義など、grid
をカスタマイズするためのあらゆる方法が解説されています。 - Grid By Exampleは、
grid
の新しい構造を作成するための出発点を探しているときに、私がよく使う場所です。 - さらに複雑な実装方法を知りたい場合は、kendo-demoアプリのframe.scssをご覧ください。
grid
を多用して、すべてのページで使用されるメニューフレームを作成しています。
参考:
Flexbox
flexbox
も同様のアプローチ(ただしまったく同じではない)で、ページ上に要素を配置し、必要に応じて自動的に調整することができます。ただし、flexbox
は複数の行と列を持つグリッドを作成するのではなく、親要素内での子要素の相対的な位置を調整するものです。
基本的には、一度に2つの方向(行と列)が必要な場合はgrid
を使用してください。1つの方向(1つの行または列)が必要な場合はflexbox
が適しています。
繰り返しになりますが、grid
とflexbox
をそれぞれいつ使用するのか、用途の違いは何なのか、は他の記事に譲ります。この記事ではflexbox
がどのようにレスポンシブ対応を処理するかにフォーカスして、不要なメディアクエリを削除できるようにします。
参考:
- CSS Gridが適しているレイアウト、Flexboxが適してるレイアウトを詳しく解説
- FlexboxとCSS Gridの使い分け方、よく見かけるUIコンポーネントをFlexboxとGridで実装するテクニックのまとめ
ここで注目したいのは、flex-wrap
プロパティです。
flex
は子要素をすべて1つの行または列に収めるようにしますが、それがうまくいかない場合は、flex-wrap: wrap;
を定義することで折り返しを許可できます。flex-wrap
が定義されていない場合は要素を縮めてすべてを同じ行に収めるか(子要素にmin-width
が指定されていない場合)、または(min-width
が指定されている場合)要素を表示されないようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
.flex { display: flex; flex-wrap: wrap; } .flex > div { width: 300px } -------- <div class="flex"> <div></div> <div></div> <div></div> </div> |
基本的にはgrid
もflex
もコンテンツを変形させたいのか、折り返したいのかを決めて、それに合わせてプロパティを定義すればよいのです。どちらも、レスポンシブなUIを作成することに適したツールです。
flexboxを使いこなしたい場合は、以下のリソースをご覧ください。
- Flexbox Froggyは愛らしいカエルのイラストを使用して、さまざまなプロパティが何をするかをマスターするのに役立つ楽しいゲームです。
- FLEXは作業中に参照できるシンプルで視覚的なチートシートです。
参考:
- CSS Flexbox 各プロパティの使い方を詳しく解説
- 独学の人でも大丈夫!CSS Flexboxの使い方を基礎から学べるチュートリアル
- CSS Flexboxで実装する時に役立つチートシート、高解像度で印刷して机の脇に貼っておくと便利です
活躍するCSSのプロパティ
大局的なレイアウトの次は、要素に特定のプロパティを定義しましょう。
朗報です、ここでもメディアクエリは必要ありません!
aspect-ratio
アスペクト比に特化されたCSSのプロパティがあるのをご存知でしたか?aspect-ratio
プロパティは、動画や大きなヒーロー画像を扱う際に正しいアスペクト比を維持させるのに非常に便利です。詳しくはCSS Tricksをご覧いただきたいのですが、実装は非常に簡単です。
1 |
.video-wrapper { aspect-ratio: 16/9; } |
aspect-ratio
と一緒にwidth
を定義するとそれが基準となり、それに合わせてheight
値が自動的に生成されます(またはその逆)。ただし、width
とheight
の両方を定義してしまうと、aspect-ratio
値よりもそちらが優先させるのでご注意ください。
参考:
- CSS aspect-ratioプロパティの基礎知識、便利な使い方、実装に必要なプログレッシブエンハンスメント
- CSS aspect-ratioプロパティの使い方、レスポンシブやレイアウトシフトで大活躍
- CSSのaspect-ratioプロパティがすべてのブラウザにサポートされました、画像をアスペクト比で実装する今までとこれからの実装方法
min-height, max-height, min-width, max-width
min
とmax
のheight
とwidth
のプロパティは多くのケースでclamp()
関数(次のセクションで説明します)に置き換えることができますが、依然として有益なCSSで、常に念頭においておくとよいでしょう。また、これらのプロパティはその言葉通りの働きをするので、簡単です。
1 2 3 4 5 |
.img { width: 100%; max-width: 50%; min-width: 200px; } |
このCSSではまず最初のwidth: 100%;
で画像サイズを最大幅までのスペースを確保するように指示し、デフォルトで最大の画像サイズになるようにしています。次にmax-width: 50%;
でコンテナ(親要素)の半分以上を占めないようにしつつ、サイズがあまり小さくなりすぎないようにmin-width: 200px;
を定義しています。
この場合、絶対値を定義するのは小さい方だけにして、画像が認識できなくなるまでにどれだけ小さくできるかを正確に把握しておきます。これでスクリーンがどんなサイズでも画像は常に可能な限り大きなサイズで表示されます。とてつもなく巨大になったり、何か分からないほど小さくなったりすることはありません。
参考:
- CSSの便利なプロパティmin-widthとmax-width、min-heightとmax-heightの効果的な使い方のまとめ
- レスポンシブ対応のレイアウトを実装する最新テクニックを解説、モバイルファーストとデスクトップファーストの現状
完全に機能するCSSの数学関数
数学関数はCSSに新しく追加されたもので、信じられないほど強力です。CSSのデベロッパーが長年にわたって不満を抱いていたもの、つまりスタイルシート内で値を計算したり、プロパティに範囲を定義する機能が使用できます。これらの関数をマスターするのが早ければ早いほど、より多くのメリットが得られます。
clamp()
clamp()
プロパティは、3つの値を定義します。基本となる推奨値を設定し、それを調整するための最小値と最大値を設定します。これはブレークポイントを定義しなくてもレスポンシブな限界値を設定できるため、メディアクエリを捨てるための最高のツールのひとつです。仕組みは以下の通りです。
1 2 3 4 |
.img { /* フォーマット clamp(最小値, 推奨値, 最大値) */ width: clamp(200px, 100%, 50%); } |
画像の幅の最小値と最大値を定義しました。このCSSではclamp()
を使用して1行で定義しています。画像は利用可能なスペースの100%
を占めますが、コンテナサイズの幅50%
より大きくなったり、200px
より小さくなることはありません。
参考:
calc()
CSSで数学ができたらいいのにと思ったことがある人には、calc()
がお勧めです。スタイルシートで、CSSの単位を使って簡単な計算ができます。これは、絶対的ではない単位に基づいて何かを計算する場合に最適です。また、計算にCSS変数を使用することで、さらに柔軟性を高めることができます。たとえば、ブラウザの現在の幅に基づいて均等に分割されたカラムを作成したいとします。
1 |
.child { width: calc(100vw / 3); } |
%を使用して幅1/3を設定することは0.333の繰り返しがあるため難しかったのですが、現在では「CSS、お前に任せる!」と言えるようになりました。このCSSでは、ブラウザの全幅(100vw
)を3
で割り、width
プロパティに設定しています。
参考:
- CSSのcalc()関数を使うとスゴイ便利!ページのレイアウト、要素やフォントのサイズ指定など実装テクニックのまとめ
- CSSの「calc()関数」を使ったレスポンシブ対応のレイアウトで高さを最適化するテクニック
- CSSのcalc()関数の使い方のまとめ -レイアウト・要素の配置・フォントサイズの定義など
min(), max()
CSSに処理を委ねたい場合には、min()
とmax()
がお勧めです。clamp()
と似た機能ですが、最小値と最大値を同時に設定するのではなく、1つだけにフォーカスし、計算結果に応じて最小値(または最大値)のみを設定します。繰り返しになりますが、固定されていない値を処理するのに非常に便利なツールで、レスポンシブなものを作成するときには何度もお世話になるプロパティです。
1 2 3 |
.img1 { width: min(30%, 200px) } .img2 { width: max(50vh, 800px) } |
2つの異なる画像の幅を設定しています。
.img1
の画像ではmin()
を使用し、200px
が親コンテナの30%
より大きいか小さいかを評価し、小さい値を採用します。
.img2
の画像ではmax()
を使用し、800px
が50vh
より大きいか小さいかを評価し、大きい値を採用します。
参考:
- CSSの比較関数 min(), max(), clamp()の使い方を詳しく解説
- CSSの数学関数min()、max()、clamp()の基本的な使い方
- しっかり理解しておくと便利なCSSのテクニック、minmax()関数の使い方
小粒だけど重要なCSSの単位
ページ上の要素をレイアウトする際に鳥瞰図のような視点で考えるのは良いことですが、小さな要素、つまりさまざまなプロパティのサイズを指定する単位についても忘れてはいけません。すべてをpx
などのハード単位で定義してしまうと、サイズを変更する必要があるたびに手動で変更しなければなりません。しかし、レスポンシブな単位を使用すれば、仕事はその単位に任せることができます!
vw, vh
CSSのレスポンシブな単位で私が好んでよく使用するのがvw
とvh
、つまりビューポート幅とビューポート高さです。パーセントの記号はありませんが、vw
とvh
はパーセントベースの単位で、1vw
はビューポート幅の1%です。
ビューポートのサイズをwindow.innerWidth
やwindow.innerLength
で取得していた時代は終わりました(これも暗黒時代の話です)。現在では、CSSでそれらの値を取得できます。また、ユーザーがウィンドウのサイズを変更すると自動的に更新されるため、ジャンプする必要もありません。
vh
は要素を垂直方向の中央に配置したり、下部に配置するときに特に便利です。たとえば、ユーザーの現在のブラウザの幅と高さに合わせたコンテナ要素を作成するには、下記のように記述するだけです。
1 2 3 4 |
.page-wrapper { height: 100vh; width: 100vh; } |
参考:
rem, em
もしまだフォントサイズをpx
で定義しているのであれば、rem
とemの素晴らしさを紹介しましょう。em
という名は古い活版印刷の測定基準に由来しており、Mの文字の幅に基づいています(これは、em-dashやen-dashという言葉の由来にもなっています(MやNの幅に等しいダッシュです)。
フォントサイズにem
を使用するときは、下記のように記述します。
1 |
.h2 { font-size: 2.5em } |
このCSSで.h2
の見出しのフォントサイズは、親要素のbody
に定義したフォントサイズの2.5倍になります。
rem
を使用すると、ページ全体のルートフォントサイズを基準にしてフォントサイズを宣言できます。rem
という名はルート(root)のem
を意味しています。rem
とem
はどちらも同じように機能しますが、違いは何をベースサイズにしているかです。そのベースサイズを基にスケーリングをおこないます。
私はem
よりrem
の方が一貫性があるため使いやすいですが、全体のスタイルとは異なる特定のエリアのデザインを作成したい場合はem
を使用します。
CSSのテクニックを探しているのであれば、vw
をrem
とclamp()
に組み合わせて、流動的なフォントサイズを定義することができます。
1 |
p { font-size: clamp(1rem, 2.5vw, 2rem); } |
フォントサイズの基準値を2.5vw
にし(1vw
はビューポート幅の1%です)、最小値と最大値を定義して、文字が読めないほど小さくなったり、大きくなりすぎないようにしています。
参考:
- CSSの比較関数が便利すぎる!min(), max(), clamp()の使い方を詳しく解説: 見出しのフォントサイズ
- デスクトップ・スマホそれぞれに適したfont-sizeの定義
- レスポンシブ対応のフォントサイズを指定するこれからのテクニック
パーセント(%)
最後になりましたが、地味だけど重要な単位%
です。grid
やflex
などのレイアウトツールではなく、何らかの理由で手書きで幅を定義する場合は、絶対的な単位ではなく、%
を使用したいと思うでしょう。
1 |
.container { width: 25%; } |
ここでは、要素が親の幅の1/4になるように設定しています。つまり、親の幅が変更されると、この要素も自動的に調整されます。シンプルですが、レスポンシブUIの構築には欠かせない要素です。
終わりに
Webサイトやアプリをレスポンシブ化するためにメディアクエリに頼っているのであれば、CSSの機能を見直して、昔ながらのブレークポイントを新しい流動的なアプローチで実装ができないか検討する時期かもしれません。
完全に流動的なスタイルのレイアウトを実装することで、ユーザーが利用する際にスマホとデスクトップでの変更は大幅に少なくなり、デザインに変更があるたびにブレークポイントを見直す必要がなくなるため、メンテナンスの手間も軽減されます。この記事で紹介したアダプティブ(適応性)のアプローチを活用して、流れに乗る準備をしてください!
sponsors