レスポンシブ ウェブ デザインの基本

インターネットでスマートフォンを使用するユーザーが増えるにつれ、ウェブデザイナーにとって、さまざまな画面サイズで適切に機能するようにコンテンツをレイアウトすることがますます重要になっています。レスポンシブ ウェブ デザインは、Ethan Marcotte が A List Apart で最初に定義したデザイン戦略で、使用しているデバイスに合わせてサイトのレイアウトを変更することで、ユーザーのニーズとデバイスの機能に対応します。たとえば、レスポンシブ サイトでは、スマートフォンではコンテンツを 1 列で表示し、タブレットでは 2 列で表示し、パソコンでは 3 列または 4 列で表示できます。

画面が広くなると、ウィジェットの形状がそれに応じて変化します。

インターネット対応デバイスにはさまざまな画面サイズがあるため、既存または将来の画面サイズにサイトを適応させることが重要です。最新のレスポンシブ デザインでは、タッチスクリーンなどの操作モードも考慮されます。すべてのユーザーにとって最適なエクスペリエンスを提供することが目標です。

ビューポートを設定する

さまざまなデバイス向けに最適化されたページには、ドキュメントのヘッダーにメタ ビューポート タグを含める必要があります。このタグは、ページのサイズと拡大縮小を制御する方法をブラウザに指示します。

最適なエクスペリエンスを提供するために、モバイル ブラウザはパソコンの画面幅(通常は 980px 程度ですが、デバイスによって異なります)でページをレンダリングし、フォントサイズを大きくして画面に収まるようにコンテンツを縮小することで、コンテンツの見栄えを良くしようとします。この調整により、フォントサイズの統一感が失われることがあります。また、コンテンツを表示して操作するためにユーザーがズームインする必要が生じることもあります。

<!DOCTYPE html>
<html lang="en">
  <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
      </head>
  

meta viewport 値 width=device-width を使用すると、ページの画面幅をデバイス非依存ピクセル(DIP)で指定できます。これは標準の視覚ピクセル単位で、高密度画面では多くの物理ピクセルで構成されます。これにより、ページのコンテンツがさまざまな画面サイズに合わせて再フローされます。

非常にズームアウトされているため、テキストが読みにくいページのスクリーンショット。
ビューポート メタタグのないページは、非常にズームアウトして読み込みされるため、テキストが読みづらくなります。Glitch の例をご覧ください。
同じページのスクリーンショット(テキストが読み取り可能なサイズ)。
ビューポート メタタグを設定すると、拡大せずにページを読むことができます。 Glitch の例をご覧ください。

一部のブラウザでは、横向きモードに回転したときにページの幅を一定に保ち、再フローの代わりに画面全体に収まるようにズームします。値 initial-scale=1 を追加すると、デバイスの向きに関係なく CSS ピクセルとデバイス非依存ピクセルの間で 1:1 の関係を設定するようにブラウザに指示し、ページで横向きの幅を最大限に活用できます。

Lighthouse 監査の width または initial-scale を含む <meta name="viewport"> タグがないは、HTML ドキュメントでビューポート メタタグが正しく使用されていることを確認するプロセスを自動化できます。

コンテンツのサイズをビューポートに合わせる

パソコンとモバイル デバイスの両方で、ユーザーはウェブサイトを縦方向にスクロールすることに慣れていますが、横方向にはスクロールしません。ページ全体を表示するために、ユーザーに横方向のスクロールやズームアウトを強制すると、ユーザー エクスペリエンスが低下します。

meta viewport タグを使用してモバイルサイトを開発する際に、指定したビューポートに収まらないページ コンテンツを誤って作成してしまうことはよくあります。たとえば、ビューポートよりも幅の広い画像を表示すると、横方向のスクロールが発生することがあります。これを回避するには、コンテンツをビューポート内に収まるように調整します。

Lighthouse 監査のコンテンツのサイズとビューポートのサイズが一致していませんは、オーバーフローするコンテンツを検出するプロセスを自動化できます。

画像

固定サイズの画像は、ビューポートよりも大きい場合、ページがスクロールされます。すべての画像に max-width100% に設定することをおすすめします。これにより、画像が使用可能なスペースに合わせて縮小され、元のサイズを超えて拡大されなくなります。

ほとんどの場合、スタイルシートに以下を追加することで、この問題を解決できます。

img {
  max-width: 100%;
  display: block;
}

画像のサイズを img 要素に追加する

max-width: 100% を設定する場合でも、<img> タグに width 属性と height 属性を追加することをおすすめします。これにより、ブラウザは画像を読み込む前に画像のスペースを予約できます。これにより、レイアウト シフトを防ぐことができます。

レイアウト

画面の寸法と CSS ピクセルの幅はデバイスによって大きく異なるため(スマートフォンとタブレット、スマートフォン同士でも異なる)、コンテンツを適切にレンダリングするために特定のビューポート幅に依存しないでください。

以前は、レイアウト要素をパーセンテージで設定する必要がありました。ピクセル単位の測定を使用すると、小さな画面でユーザーが横方向にスクロールする必要があります。

2 列レイアウトのスクリーンショット(2 列目のほとんどがビューポートの外側にある)
ピクセルを使用したフローティング レイアウト。Glitch の例をご覧ください。

代わりにパーセンテージを使用すると、各列が常に画面幅の同じ割合を占めるため、小さい画面では列が狭くなります。

Flexbox、グリッド レイアウト、マルチコラムなどの最新の CSS レイアウト手法を使用すると、このような柔軟なグリッドを簡単に作成できます。

Flexbox

サイズの異なるアイテムのセットを 1 行または複数の行に収める場合は、Flexbox を使用します。小さいアイテムはスペースをあまり使用せず、大きいアイテムはスペースを多く使用します。

.items {
  display: flex;
  justify-content: space-between;
}

Flexbox を使用すると、アイテムを 1 行として表示したり、使用可能なスペースが減るにつれて複数の行に折り返したりできます。

Flexbox の詳細

CSS グリッド レイアウト

CSS グリッド レイアウトを使用すると、柔軟なグリッドを作成できます。グリッド レイアウトと fr 単位(コンテナ内の使用可能なスペースの一部を表します)を使用すると、前述のフローティングの例を改善できます。

.container {
  display: grid;
  grid-template-columns: 1fr 3fr;
}

グリッド レイアウトを使用して、収まるだけ多くのアイテムを含む通常のグリッド レイアウトを作成することもできます。画面サイズが小さくなると、使用可能なトラック数が減ります。次のデモは、各行に収まるカードをすべて含むグリッドを示しています。最小サイズは 200px です。

CSS グリッド レイアウトの詳細

複数列レイアウト

レイアウトによっては、複数列レイアウト(マルチコラム)を使用できます。このレイアウトでは、column-width プロパティを使用して、レスポンシブな数の列を作成します。次のデモでは、別の 200px 列を追加するスペースがある場合に、ページに列が追加されます。

Multicol の詳細

レスポンシブに CSS メディアクエリを使用する

特定の画面サイズをサポートするために、前述の方法では許容されないほど、レイアウトに大幅な変更を加える必要がある場合があります。ここでメディアクエリが役立ちます。

メディアクエリは、CSS スタイルに適用できるシンプルなフィルタで、コンテンツをレンダリングするデバイスの種類に基づいてスタイルを変更できます。また、幅、高さ、向き、デバイスがタッチスクリーンとして使用されているかどうかなど、デバイスの機能に基づいてスタイルを変更することもできます。

印刷用に異なるスタイルを提供するには、出力タイプをターゲットに設定し、印刷スタイルのスタイルシートを含めます。

<!DOCTYPE html>
<html lang="en">
  <head>
        <link rel="stylesheet" href="print.css" media="print">
      </head>
  

メディアクエリを使用して、メインのスタイルシートに印刷スタイルを含めることもできます。

@media print {
  /* print styles go here */
}

レスポンシブ ウェブデザインでは、デバイスの機能に関するクエリが最も一般的であるため、タッチスクリーンや小画面向けにレイアウトをカスタマイズできます。

ビューポートのサイズに基づくメディアクエリ

メディアクエリを使用すると、特定の画面サイズに特定のスタイルを適用するレスポンシブなエクスペリエンスを作成できます。画面サイズのクエリでは、次の項目をテストできます。

  • widthmin-widthmax-width
  • heightmin-heightmax-height
  • orientation
  • aspect-ratio

これらの機能はすべて、優れたブラウザ サポートが提供されています。ブラウザのサポート情報など、詳細については、MDN の widthheightorientationaspect-ratio をご覧ください。

デバイスの機能に基づくメディア クエリ

デバイスの種類が非常に多いため、デベロッパーは、大きなデバイスはすべて通常のデスクトップ パソコンまたはノートパソコンであり、小さなデバイスはすべてタッチスクリーンを使用しているとは限りません。メディアクエリ仕様に最近追加された機能を使用すると、デバイスの操作に使用されるポインタのタイプや、ユーザーが要素の上にポインタを保持できるかどうかなどの機能をテストできます。

  • hover
  • pointer
  • any-hover
  • any-pointer

通常のデスクトップ パソコン、スマートフォン、タブレットなど、さまざまなデバイスでこのデモを表示してみてください。

これらの新しい機能は、すべての最新ブラウザで十分にサポートされています。詳しくは、MDN のhoverany-hoverpointerany-pointer のページをご覧ください。

any-hoverany-pointer を使用する

any-hoverany-pointer の機能は、ユーザーが要素の上にポインタを保持できるかどうか(多くの場合、ホバーと呼ばれます)をテストします。また、デバイスの操作の主な方法ではない場合でも、ポインタを使用できるかどうかもテストします。これらの機能を使用する際は十分に注意してください。たとえば、タッチスクリーン ユーザーがマウスに切り替えざるを得ないようにしないでください。ただし、ユーザーが使用しているデバイスの種類を特定することが重要である場合は、any-hoverany-pointer が役立ちます。たとえば、タッチスクリーンとトラックパッドを備えたノートパソコンは、ホバー機能に加えて、粗いポインタと細かいポインタに対応している必要があります。

ブレークポイントを選択する方法

デバイスクラス、プロダクト、ブランド名、オペレーティング システムに基づいてブレークポイントを定義しないでください。これにより、コードの保守が困難になります。代わりに、コンテナに合わせてレイアウトを変更する方法をコンテンツに決定させます。

小さく始めて徐々に大きくすることで、主要なブレークポイントを選択する

まず小さい画面サイズに収まるようにコンテンツを設計し、ブレークポイントが必要になるまで画面を拡大します。これにより、ページのブレークポイントの数を最小限に抑え、コンテンツに基づいて最適化できます。

次の例では、このページの冒頭にある天気予報ウィジェットの例について説明します。最初のステップは、予測を小さい画面に適切に表示することです。

モバイル幅の天気アプリのスクリーンショット
幅が狭いアプリ。

次に、要素間の空白が広すぎてウィジェットが見づらくなるまでブラウザのサイズを変更します。判断は主観的ですが、600px を超えると明らかに広すぎます。

アイテム間に大きな間隔がある天気アプリのスクリーンショット
このサイズでは、アプリのレイアウトを変更する必要があります。

600px にブレークポイントを挿入するには、コンポーネントの CSS の末尾に 2 つのメディアクエリを作成します。1 つはブラウザが 600px 以下の場合、もう 1 つは 600px より大きい場合に使用します。

@media (max-width: 600px) {

}

@media (min-width: 601px) {

}

最後に、CSS をリファクタリングします。600pxmax-width のメディアクエリ内に、小画面専用の CSS を追加します。601pxmin-width のメディアクエリ内に、大きな画面用の CSS を追加します。

必要に応じてマイナーなブレークポイントを選択する

レイアウトが大幅に変更される場合は、主要なブレークポイントを選択するだけでなく、マイナーな変更に合わせて調整することも役立ちます。たとえば、主要なブレークポイント間で、要素の余白やパディングを調整したり、フォントサイズを大きくしてレイアウトをより自然に見せたりすることが役立ちます。

この例では、前の例と同じパターンに沿って、小さい画面のレイアウトを最適化します。まず、ビューポートの幅が 360px より大きい場合にフォントを大きくします。その後、十分なスペースがある場合は、最高気温と最低気温を分けて同じ行に配置し、天気アイコンを大きくすることができます。

@media (min-width: 360px) {
  body {
    font-size: 1.0em;
  }
}

@media (min-width: 500px) {
  .seven-day-fc .temp-low,
  .seven-day-fc .temp-high {
    display: inline-block;
    width: 45%;
  }

  .seven-day-fc .seven-day-temp {
    margin-left: 5%;
  }

  .seven-day-fc .icon {
    width: 64px;
    height: 64px;
  }
}

大きな画面の場合は、画面全体の幅を使用せずに、予報パネルの最大幅を制限することをおすすめします。

@media (min-width: 700px) {
  .weather-forecast {
    width: 700px;
  }
}

読み上げ用にテキストを最適化する

古典的な読みやすさの理論では、理想的な列は 1 行あたり 70 ~ 80 文字(英語では約 8 ~ 10 単語)に収める必要があります。テキスト ブロックの幅が約 10 単語を超えるたびに、ブレークポイントを追加することを検討してください。

モバイル デバイス上のテキスト ページのスクリーンショット
モバイル デバイス上のテキスト。
パソコンのブラウザで表示されたテキストのページのスクリーンショット
行の長さを制限するためにブレークポイントが追加された、パソコンのブラウザでの同じテキスト。

この例では、1em の Roboto フォントは小さい画面では 1 行あたり 10 単語を生成しますが、大きな画面ではブレークポイントが必要です。この場合、ブラウザの幅が 575px より大きい場合、理想的なコンテンツの幅は 550px です。

@media (min-width: 575px) {
  article {
    width: 550px;
    margin-left: auto;
    margin-right: auto;
  }
}

コンテンツを非表示にしないこと(:#avoid-hiding-content)

画面サイズに応じて非表示または表示するコンテンツを選択する際は、注意してください。コンテンツが画面に収まらないからといって、コンテンツを非表示にしないでください。画面サイズは、ユーザーが何を表示したいかを予測するものではありません。たとえば、花粉数を天気予報から削除すると、春のアレルギーに苦しむ人にとって深刻な問題になる可能性があります。花粉数は、外出できるかどうかを判断するために必要な情報です。

Chrome DevTools でメディアクエリのブレークポイントを表示する

メディアクエリのブレークポイントを設定したら、サイトの表示にどのように影響するかを確認します。ブラウザ ウィンドウのサイズを変更してブレークポイントをトリガーすることもできますが、Chrome DevTools には、さまざまなブレークポイントでページがどのように表示されるかを確認できる機能が組み込まれています。

天気アプリが開いていて、幅が 822 ピクセルに設定されている DevTools のスクリーンショット。
広いビューポート サイズで天気アプリを表示している DevTools。
天気アプリが開いていて、幅が 436 ピクセルに設定されている DevTools のスクリーンショット。
ビューポートのサイズが狭い天気アプリを表示している DevTools。

さまざまなブレークポイントでページを表示するには:

  1. DevTools を開きます
  2. [デバイスモード] をオンにします。デフォルトではレスポンシブ モードで開きます。
  3. メディアクエリを表示するには、デバイスモード メニューを開き、[メディアクエリを表示] を選択します。ページの上部に、色付きのバーとしてブレークポイントが表示されます。
  4. バーのいずれかをクリックすると、そのメディアクエリがアクティブな状態でページが表示されます。バーを右クリックすると、そのメディアクエリの定義に移動します。