レスポンシブ Web デザイン 作成資料

作成日:2018年3月3日

レスポンシブ Web デザインは、単一の HTML を画面のサイズに応じて適用する CSS を切り替えることで、PC、タブレット、スマートフォンなどのデバイスに最適化したデザイン・レイアウトを設定して表示する手法のことです。

レスポンシブ Web デザインに対応したページを作成するには、以下のようなテクニックを使用します。

  • Viewport の設定(デバイスの幅に応じた表示サイズの設定)
  • メディアクエリを使った、画面サイズに合わせたレイアウトの切り替え
  • 画面サイズに合わせて伸縮するレイアウト(相対的な単位の使用)
  • 画面サイズや解像度にに合わせて画像を最適化

Viewport(ビューポート)

スマートフォンの多くは Viewport(ビューポート)と呼ばれる仮想ウィンドウサイズが設定されていて、設定された Viewport サイズに従って Web ページを表示します。

Viewport にはブラウザの表示領域を「何ピクセル X 何ピクセル」で表示するかの値が px 単位で設定されていて、デバイスごとにデフォルトのサイズが異なります。(デバイスの幅や解像度とは違います)

PC とは異なり、スマートフォンではブラウザは常に全画面表示されますが、ウィンドウサイズの挙動(何ピクセルの幅で表示するか)は Viewport によって決められます。

以下の JavaScript (document.documentElement.clientWidth) は、ブラウザの横幅を検出します。実行すると、PC ではウィンドウ幅が検出され、iPhone や Androidでは(Viewport を指定していない場合は、デフォルトの値) 980 が検出されます。

<p class="c_width">clientWidth : <span></span> px</p>

<script>
jQuery(function($){ 
  $(".c_width span").text(document.documentElement.clientWidth);
});
</script> 

つまり、スマートフォンではデフォルトの場合、仮想的に 980px のブラウザで閲覧していることになります。

また、以下を実行すると、デバイスピクセル比を検出することができます。PC ではデバイスピクセル比は「1」ですが、解像度の高いスマートフォンでは「2」などが表示されます。

<p class="dpr">devicePixelRatio : <span></span></p>

<script>
jQuery(function($){ 
  $(".dpr span").text(window.devicePixelRatio);
});
</script>
デフォルトの Viewport サイズの例
OS ブラウザ 標準 Viewport サイズ(幅)
iOS(Phone) Safari 980px
Android Android 800px
Windows Phone Mobile Internet Exploler 1024px
Opera Mobile 850px

デバイスピクセル比(device-pixel-ratio)

デバイスピクセル比とは画像の1ピクセルをデバイスの画面で何ピクセルとして描画するかを表した数値です。この比率を利用することで、高解像度のディスプレイでも通常の解像度のディスプレイと見た目のサイズが同じように表示されるようになっています。

例えば、100px X 100px の画像はデバイスピクセル比が 1 のデバイスでは PC と同様 100px X 100px のデバイスピクセルで描画されますが、デバイスピクセル比が 2 のデバイスでは 200px X 200px のデバイスピクセルで描画されます。

デバイスの解像度(device-width や device-height)は、スマートフォンなどではデバイスピクセル比から求められた解像度の値になります。これは「デバイスの画面解像度 ÷ デバイスピクセル比」で求めることができます。

例えば、画面解像度が 640px X 1136px、デバイスピクセル比「2」の iPhone 5 では 320px X 568px となります。

以下のサンプルでは、ブラウザの幅や高さ、デバイスピクセル比(device-pixel-ratio)を検出して表示します。最初のサンプルをスマートフォンで確認すると、そのデバイスの仮想ウィンドウサイズを確認できます。(clientWidth の値)

viewport の設定による表示の違いの画像(iPhoneの場合の例)

Viewport の設定

Viewport はスマートフォン等での Web ページの表示方法を制御します。Viewport の設定がない場合、スマートフォン等では一般的なデスクトップ画面の幅(上記表参照)でページをレンダリングします。Viewport を設定すると、ページの幅やさまざまな端末での拡大縮小を制御できるようになります。

レスポンシブデザインでは、メディアクエリを使って表示領域によってレイアウトを変化させるので、Viewport を適切に設定して、想定したスタイルが適用されるようにする必要があります。

Viewport は、HTML の head 要素内に meta タグを使って記述して制御できるようになっていて、以下が書式です。Viewport のプロパティを複数指定する場合はカンマ「,」で区切って指定します。

<meta name="viewport" content="プロパティ">

以下はレスポンシブデザインで良く使用される Viewport の設定例です。

<meta name="viewport" content="width=device-width, initial-scale=1">
        
<!-- 以下は iOS 9 バグ対応に shrink-to-fit=no を追加  -->  
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

デバイスの横幅に合わせてコンテンツを表示する場合は、viewport の値を「width=device-width」として指定することで、解像度と viewport を一致させることができます。

そのため、viewport の幅(width)の値は、「device-width」が一般的に使用されます。

初期拡大率(initial-scale)を指定していない場合、ページのコンテンツが device-width より大きい場合は、コンテンツが全て表示されるように自動的に縮小されて表示されます。

初期拡大率を initial-scale=1 と指定すると、縮小されずに表示されます。また、属性 initial-scale=1 を追加することで、デバイスの向きに関係なく CSS ピクセルとデバイス非依存ピクセルとの間に 1:1 の関係を確立するようブラウザに指示が与えられ、横向きにした場合にページ幅全体を利用できるようになります。(iPhone を縦から横へ回転させた時に、Web ページが拡大表示されるのを防ぐことができます)

Viewport のプロパティの設定では、ユーザーによる拡大・縮小操作の制御や表示倍率なども設定することができます。

Viewport のプロパティ
プロパティ 意味
width 任意の幅に px で指定 200~10,000px または
device-width(デバイスの幅に合わせる)
height 任意の高さに px で指定 200~10,000px または
device-height(デバイスの高さに合わせる)
initial-scale 最初の縮小率を 0~10.0 の範囲で指定 0~10.0(デフォルト:0.25)
minimum-scale 最小の縮小率を 0~10.0 の範囲で指定 0~10.0(デフォルト:0.25)
maximum-scale 最大の拡大率を 0~10.0 の範囲で指定 0~10.0(デフォルト:1.6)
user-scalable ユーザーによる拡大・縮小の許可を指定 yes (有効)または no (無効)
無効にするとユーザーは拡大・縮小ができなくなる

但し、以下のプロパティを設定するとユーザーがビューポートをズームできなくなる場合があり、ユーザビリティやアクセシビリティに問題が生じる可能性があるので注意が必要です。

  • minimum-scale
  • maximum-scale
  • user-scalable

以下は Viewport の記述例です。

<!DOCTYPE HTML>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>レスポンシブ Web デザイン</title>
<link rel="stylesheet" href="../css/style.css">
</head>
<body>
・・・中略・・・
</body>
</html>

Media Queries(メディアクエリ)

レスポンシブ Web デザインでは、メディアクエリを使ってスクリーン幅などに応じて CSS を切り替えます。

メディアクエリを使用すると、画面の種類、幅、高さ、向き、解像度など、デバイスの特性に基づいて、スタイルを容易に切り替えることができます。

メディアクエリはデバイスの解像度、ウィンドウの幅、向きなどの指定条件に合わせて別々の CSS を適用できる機能です。link 要素中の media 属性や CSS の @media 規則を使ってデバイスやスクリーンサイズで適用範囲を切り替えることができます。

link 要素を利用して複数ファイルを読み込むより、@media の方が HTTP リクエストの回数が少なくページの読み込みが早くなります。

以下は link 要素中の media 属性を使った例です(ブラウザの幅が 640px 以上の場合、min-640px.css を適用)。

<link rel="stylesheet" media="(min-width: 640px)" href="min-640px.css">

以下は CSS の @media 規則を使った例です(ブラウザの幅が 768px~960px の場合、@media 内のスタイルを適用)。

@media (min-width: 768px) and (max-width: 960px) {
   /* ここに幅が768px~960pxまでの CSS を記述 */
}

メディアクエリの書式

メディアクエリの書式には、いくつかのパターンがありますが、以下がレスポンシブ Web デザインで良く使われる書式です。

@media メディアタイプ and (条件) {
  /* 条件に合った場合に適用される CSS */
}

/* 例 */
@media screen and (min-width: 768px) {
  .container {
    width: 750px;
  }
}

メディアタイプ(出力先)はスマートフォンやタブレット、PC などのディスプレイに表示する CSS を記述する場合は、screen を指定します。

メディアタイプの種類
メディアタイプ デバイスの種類(説明)
all すべてのデバイス
screen ディスプレイ (PC、タブレット、スマートフォン)
print プリンター
speech 音声出力デバイス
tv テレビ
projection プロジェクター
handheld モバイルデバイス(携帯電話)
tty テレタイプなどの固定幅フォントで出力するデバイス
braille 点字用ディスプレイ
embossed 点字用プリンター

not 演算子や only 演算子のどちらも指定されていない場合はメディアタイプは省略可能で、その場合にはメディアタイプ all(すべてのデバイス)が適用されます。

言い換えると、メディアタイプに all(すべてのデバイス)を指定するときは、all と and の記述を省略することができます(但し、not 演算子、 only 演算子のどちらも使用していない場合)。

/* all と and の記述を省略する例 (メディアタイプ all が適用される)*/
@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}

条件

条件(メディア特性:値)部分のメディア特性には、以下のようなキーワードを指定することができます。ほとんどのメディア特性は、「以上」や「以下」といった条件を付けるために "min-" や "max-" という接頭辞を付けることができます。

メディア特性
キーワード 概要
width ディスプレイの幅。min-width や max-width が良く使われます。
幅が480px以上、かつ960px以下のデバイスにスタイルシートを適用する場合
@media (min-width:480px) and (max-width:960px) { ... }
height ディスプレイの高さ。min-height や max-height を使用可能。実際には「ディスプレイの高さ」を条件にするケースはあまりありません。
device-width 表示領域(物理的な画面サイズ)の幅。Web の表示領域ではなく、端末の画面サイズを基準に判別するため、ブラウザのウィンドウサイズを変更しても変化しない。(レスポンシブデザインでは、通常使用しない)
device-height 表示領域(物理的な画面サイズ)の高さ。Web の表示領域ではなく、端末の画面サイズを基準に判別するため、ブラウザのウィンドウサイズを変更しても変化しない。(レスポンシブデザインでは、通常使用しない)
orientation デバイスの向き。縦向き:portrait、横向き:landscape
ディスプレイが縦向きであればスタイルシートを適用する場合
@media all and (orientation: portrait) { ... }
但し、この機能はPCでも機能するので、例えば landscape の場合、ブラウザの画面を横長にすると有効になります。 そのため、実際に使用する場合は、以下のように画面幅の条件も併記するなどの工夫が必要になります。
@media only screen and (max-width:640px) and (orientation: landscape) { ... }
aspect-ratio ディスプレイの縦横比。この値はスラッシュ("/")で区切られた 2 つの正整数で指定され、水平方向 / 垂直方向のようにピクセル数の比を表します。
縦幅以上の横幅を持つディスプレイにスタイルシートを適用する場合
@media screen and (min-aspect-ratio: 1/1) { ... }
device-aspect-ratio 表示領域(物理的な画面サイズ)の縦横比。この値はスラッシュ("/")で区切られた 2 つの正整数で指定され、水平方向 / 垂直方向のようにピクセル数の比を表します。
アスペクト比が 16:9のディスプレイにスタイルシートを適用する場合
@media screen and (device-aspect-ratio: 16/9) { ... }
color カラーディスプレイの色のビット数
色深度が 4 ビット以上のデバイスにスタイルシートを適用する場合
@media all and (min-color: 4) { ... }
color-index カラールックアップテーブルの数
256 色以上のインデックスカラーを使用しているデバイスにスタイルシートを適用する場合
@media all and (min-color-index: 256) { ... }
monochrome 白黒ディスプレイのビット数(bits per pixel )。カラーディスプレイの場合は「0」
すべてのモノクロデバイスにスタイルシートを適用する場合
@media all and (monochrome) { ... }
resolution ディスプレイの解像度。解像度は dots per inch(dpi)か dots per centimeter(dpcm)のどちらでも指定できます。
300dpi 以上の解像度を持つデバイスにスタイルシートを適用する場合
@media print and (min-resolution: 300dpi) { ... }
scan メディアタイプが tv の場合の画面の走査方法。値は progressive、または interlace。
プログレッシブ方式で走査するテレビにスタイルシートを適用する場合
@media tv and (scan: progressive) { ... }
grid 出力デバイスがグリッド式であるかビットマップ式であるかを指定。グリッドデバイス(TTY ターミナルや携帯電話のディスプレイのように単一のフォントを有するもの)の場合は「1」。それ以外は「0」
ディスプレイ幅が 15 文字以内のモバイル端末にスタイルシートを適用する場合
@media handheld and (grid) and (max-width: 15em) { ... }

min-device-width についての注意

min-device-width を基準にしたクエリも作成できますが、以下のような問題がありこの方法は使用しない方が良いようです。(レスポンシブ ウェブデザインの基本/developers.google.com より抜粋 )

一部のブラウザ(以前の Android ブラウザを含む)ではデバイスの幅が正しく通知されず、期待されるビューポートの幅の代わりに、画面サイズがデバイス ピクセルで通知される場合があります。

さらに、min-device-width を使用すると、ウィンドウのサイズ変更が可能なパソコンや他のデバイスでコンテンツが対応しないことがあります。これは、クエリがブラウザ ウィンドウのサイズではなく実際のデバイスのサイズに基づいているためです。

さまざまなメディア特性についてクエリを記述できますが、レスポンシブ Web デザインでは、以下のメディア特性がよく使用されます。

キーワード 説明
min-width ブラウザの幅の値がクエリに定義された値よりも大きい場合
max-width ブラウザの幅の値がクエリに定義された値よりも小さい場合
min-height ブラウザの高さの値がクエリに定義された値よりも大きい場合
max-height ラウザの高さの値がクエリに定義された値よりも小さい場合
orientation portrait: ブラウザの高さが、幅と同じかそれ以上の場合
landscape: ブラウザの幅が、高さよりも大きい場合

論理演算子

and や not、only といった論理演算子を用いて、複雑なメディアクエリを組み立てることができます。

and 演算子

and 演算子は複数の条件(メディア特性)を互いに連結したり、メディア特性とメディアタイプを連結したりするのに用いられます。

and で連結した場合、全ての条件に一致するデバイスを対象にすることができます。

以下の例は、メディアタイプが screen で、かつビューポート横幅が 480px 以上、かつ 960px 以下のデバイスを対象としています。

@media screen and (min-width:480px) and (max-width:960px){
  * {font-size: 14px; }  
}

カンマ区切りリスト

メディアクエリに含まれたカンマ区切りのリストは or 演算子と同じような働きをします。

カンマ区切りリストの場合は、条件のうち1つ以上に一致したデバイスを対象にすることができます。

以下の例は、横幅が 700px 以上のデバイス、または横向きのモバイル端末の両方にスタイルを適用します。

@media (min-width: 700px), handheld and (orientation: landscape) {
  ... 
}

not 演算子

先頭に not 演算子を入れると、その条件に一致しないデバイスを対象にすることができます。

not 演算子は個別のメディア特性を否定することはできず、常にメディアクエリ全体に対して用いられます。

@media not all and (max-width: 640px) { 
  ... 
}

上記のクエリは次のように評価され、ビューポートの横幅が 640px 以内ではないデバイス(横幅が 641px 以上のデバイス)にスタイルが適用されます。

@media not (all and (max-width: 640px)) { 
  ... 
}

only 演算子

先頭に only 演算子を入れると、メディアクエリに対応していない古いブラウザを除外することができます(メディアクエリに対応していないブラウザには CSS を読み込ませないようにできます)。

@media only screen and (min-width: 640px){ 
  ... 
}

上記のクエリの場合、メディアクエリに対応しているブラウザであれば、only 以降のメディアクエリが処理されますが、メディアクエリに対応していないブラウザでは、only というキーワードが認識できずこの条件は適用されません(古いブラウザからスタイルシートを隠します)。

メディアクエリの記述順

CSS では、後から記述したスタイルにより値が上書きされます。このため、スタイルを記述する順番を間違えるとメディアクエリが正しく機能しない場合があります。

以下は、h1 要素のスタイルを指定した例です。

/* 間違った記述順の例 */
@media (max-width: 575px) {
  h1 {
    color: green;
  }
}

h1 {
  color: red;
}

上記は画面幅が 575px 以下のときは文字色を緑色、それ以外の場合は文字色を赤色で表示するように意図して記述したものですが、実際には常に赤色で表示されてしまいます。

上記の場合、画面幅が 575px 以下のときは h1 { color: green; }(文字色を緑色)が有効になりますが、その直後にh1 { color: red; }があり、この指定は画面幅によらないため 575px 以下でも適用されてしまい、結果として常に赤色で表示されていまいます。以下のように記述すると意図したような結果が得られます。

h1 {
  color: red;
}
@media (max-width: 575px) {
  h1 {
    color: green;
  }
}

以下は画面幅が 575px 以下のときは文字色を緑色、767px 以下のときは文字色を青色、それ以外の場合は文字色を赤色で表示するように意図して記述したものですが、実際にはそのようにはなりません。

/* 間違った記述順の例 */
h1 {
  color: red;
}

@media (max-width: 575px) {
  h1 {
    color: green;
  }
}
 
@media (max-width: 767px)  {
  h1 {
    color: blue;
  }
}

上記の場合、767px より大きい場合は2つのメディアクエリは無視され、文字色は赤色になり想定どおりです。

576px~767px の場合は、@media (max-width: 575px) は無視され、@media (max-width: 767px) が適用されて、文字色は青色になり想定どおりです。

575px 以下の場合は、@media (max-width: 575px) が適用されますが、同時に @media (max-width: 767px) も有効なため適用されてしまい(575px 以下ということは、767px 以下という条件にも合致するため)文字色は青色になり想定どおりにはなりません。

画面幅が 575px 以下のときは文字色を緑色、767px 以下のときは文字色を青色、それ以外の場合は文字色を赤色で表示するようにするには、以下のような順序で記述します。

h1 {
  color: red;
}

@media (max-width: 767px)  {
  h1 {
    color: blue;
  }
}

@media (max-width: 575px) {
  h1 {
    color: green;
  }
}

min-width を使って書き換えると以下のようになります。

/* min-width を使った正しい記述順の例 */ 
h1 {
  color: green;
}

@media (min-width: 576px) {
  h1 {
    color: blue;
  }
}

@media (min-width: 768px)  {
  h1 {
    color: red;
  }
}

サンプル

基本的には、「幅△△以下 @media (max-width: △△px)」を条件にする場合は、サイズの大きいものから順番にメディアクエリを記述していきます。

@media (max-width: 1199px) { ... }

@media (max-width: 991px) { ... }  
  
@media (max-width: 767px) { ... }  

@media (max-width: 575px) { ... }

逆に「幅△△以上 @media (min-width: △△px)」を条件にする場合(モバイルファースト等)は、サイズの小さいものから順番にメディアクエリを記述していきます。

@media (min-width: 576px) { ... }
 
@media (min-width: 768px) { ... }
 
@media (min-width: 992px) { ... }
 
@media (min-width: 1200px) { ... }

メディアクエリで使う単位

ここの例では、@media only screen and (min-width: 640px) のようにメディアクエリで使う単位に px を使用しています。

メディアクエリで使う単位には、px の他に em や rem を使用することもできます。以下は参考サイトです。

Media Queriesで使う単位はpx, em, remのどれが適しているか検証 -px指定は注意が必要

ブレークポイント

メディアクエリを使った CSS の切り替えでは、CSS を切り替える条件である「ブレークポイント(Break Point)」を決め、それぞれの条件に沿ったスタイルシートを記述します。

ブレークポイントとは、メディアクエリによって CSS を切り替える条件となるポイント(レイアウトを切り替える画面サイズの値)のことです。

通常、スマートフォン、タブレット、PC(更に大画面 CPなど)を想定してブレークポイントを設定しますが、その際に市販されているデバイスサイズを元にブレークポイントを設定するのは、デバイスのサイズが常に変わってきているため望ましくありません。

以下は、「レスポンシブ ウェブデザインの基本/developers.google.com」からの抜粋 です。

ブレークポイントは、デバイスクラスを基準に設定しないでください。現在使用されている特定のデバイス、製品、ブランド名、オペレーティング システムを基準にブレークポイントを設定すると、メンテナンスが非常に大変になる可能性があります。代わりにコンテンツ内容に基づいて、コンテナに合ったレイアウト方法を決定するようにしてください。

  • 特定のデバイス、製品、ブランドではなく、コンテンツ内容に基づいてブレークポイントを作成します。
  • まず、サイズが最小のモバイル端末向けにデザインします。その後、使用できる画面領域の増加に合わせて段階的にエクスペリエンスを拡張します。
  • 一行に表示する文字数は最大で 70~80 文字程度にします。

普及しているデバイスの画面幅を調べて、そこからブレークポイントを割り出すのではなく、作成するコンテンツが最適に見えるブレークポイントを探す必要があります。つまりコンテンツのデザインにより、ブレークポイントの値や数は変わってくるということになります。

ある幅で見たときにどのレイアウトが見やすいかを基準に決めていきます。具体的には、まずは小さな画面にコンテンツが収まるようにデザインし、ブレークポイントが必要となるまで画面を広げていきます。 こうすることで、コンテンツに基づいて最適なブレークポイントを設定します。

モバイルファースト

モバイルファースト(Mobile First)とは、サイトの設計・デザインをする際に、モバイルを基点として始め、PC に展開していくコンセプトです。

メディアクエリの記述もモバイルファースト(スマートフォンなどの小さなスクリーン用から記述していく方法)で行うと効率的に記述することができます。

例えば、以下のように記述した場合、スマートフォンなどのモバイル端末では無駄な処理が発生してしまいます。スマートフォンなどのモバイル端末など画面幅が 767px より小さい場合、最初に padding: 20px; が適用され、その後メディアクエリにより padding: 0; のスタイルが上書きされることになります。

つまり、最初に指定されたスタイル padding: 20px; の読み込みは無駄な処理になります。

モバイル端末では、PC より処理能力が低い場合が多く、またモバイル通信の速度も遅いため、このような処理が多ければ、ページが表示されるまでの時間が長くなってしまいます。

@charset "utf-8";
body {
  padding: 20px;
}
@media screen and (max-width : 767px){
  body {
    padding: 0;
  }
}

以下のように記述(min-width を使ってメディアクエリを記述)することで、モバイル端末では無駄な処理が発生しなくなります。モバイル端末では padding: 0; のスタイルが適用され、PC など 768px 以上の端末では、padding: 20px; が適用されます。

@charset "utf-8";
body {
  padding: 0;
}
@media screen and (min-width : 768px){
  body {
    padding: 20px;
  }
}

モバイル(スマートフォン)向けのデザインは、一般的に PC 向けのデザインよりシンプルな場合が多いので、モバイル向けの CSS を最初に記述しておき、メディアクエリの中で PC 向けなどの差分の CSS を記述します。

具体的には、メディアクエリを指定していない部分の CSS には、デスクトップを含めた全てのデバイスにおいて共通で利用するスタイル及びスマートフォンに最適化したレイアウト記述します。

そして、メディアクエリを使った部分では、メディアクエリを指定していないデフォルトのスタイルシートとの差分を記述します。

@charset "utf-8";
/* デフォルト(480px 未満)
   デバイスで共通で利用するスタイル
   スマートフォンに最適化したレイアウト
  */
@media screen and (min-width : 480px){
  /* 最小幅 480px 以上の指定 */
}
@media screen and (min-width : 768px){
  /* 最小幅 768px 以上の指定 */
}
@media screen and (min-width : 1024px){
  /* 最小幅 1024px 以上の指定 */
}

以下は Bootstrap 4 のブレークポイントの例ですが、こちらもモバイルファーストになっています。想定している幅は以下のようになっています。

  • Extra small devices:スマートフォン(縦向き)などの小さなデバイス(576px 未満)
  • Small devices:スマートフォン(横向き)(576px~767px)
  • Medium devices:タブレット(768px~991px)
  • Large devices:デスクトップPC(992px~1199px)
  • Extra large devices:大型デスクトップPC(1200px以上)
// Extra small devices (portrait phones, less than 576px)
// No media query since this is the default in Bootstrap

// Small devices (landscape phones, 576px and up)
@media (min-width: 576px) { ... }

// Medium devices (tablets, 768px and up)
@media (min-width: 768px) { ... }

// Large devices (desktops, 992px and up)
@media (min-width: 992px) { ... }

// Extra large devices (large desktops, 1200px and up)
@media (min-width: 1200px) { ... }

また、Bootstrap 4 では、必要に応じて以下のような max-width を使ったメディアクエリも使用しています。(「メディアクエリの記述順」で注意した順序と異なりますが、この順序でも問題ないような指定の内容になっています。)

// Extra small devices (portrait phones, less than 576px)
@media (max-width: 575px) { ... }

// Small devices (landscape phones, less than 768px)
@media (max-width: 767px) { ... }

// Medium devices (tablets, less than 992px)
@media (max-width: 991px) { ... }

// Large devices (desktops, less than 1200px)
@media (max-width: 1199px) { ... }

// Extra large devices (large desktops)
// No media query since the extra-large breakpoint has no upper bound on its width

マイナー ブレークポイント

レイアウトが大きく変化する場合のメジャー ブレークポイントの選択に加えて、メジャー ブレークポイントの間で、要素の余白やパディングを調整したり、レイアウトになじむようにフォントサイズを調整したりします。

古い IE への対応

必要であれば以下のような対処をします。

IE8 以下では Media Queries は動作しないので、Media Queries を有効にするライブラリを利用します。

css3-mediaqueries-js
CSS 内の @media 規則のみを解析する。
HTML 内の link 要素で指定した場合や CSS 内の @import で読み込ませた場合は無効。
Respond.js
HTML 内の link 要素かつ rel 属性が stylesheet に指定された stylesheet または、CSS 内の @media 規則のみを解析する。
CSS 内の @import 規則は無効

Respond.js の読み込みの例

ダウンロードした JavaScript ファイルをコンディショナル・コメント(IE9未満のみ適用)を使って head 要素内の全ての CSS ファイルの後に読み込みます。

<head>
....
<!--[if lt IE 9]>
<script src="js/respond.min.js"></script>
<![endif]--> 
....
</head>

また、IE9 以前のバージョンでは、HTML5 に対応していないので、IE の旧来のバージョンのブラウザでも HTML5 を認識し追加要素がブロックレベル要素として認識されるように「html5shiv (https://github.com/afarkas/html5shiv)」というライブラリをダウンロードして head 要素内(respond.min.js の読み込みの直前)で読み込みます。

ダウンロードしたファイルを解凍して、html5shiv.js と html5shiv-printshiv.js の2つのファイルをコピー(配置)して、どちらかを読み込みます。(原文:Download and extract the latest zip package from this repositiory and copy the two files dist/html5shiv.js and dist/html5shiv-printshiv.js into your project. Then include one of them into your <head> as above.)

<head>
....
<!--[if lt IE 9]>
<script src="assets/js/html5shiv-printshiv.js"></script>
<script src="assets/js/respond.min.js"></script>
<![endif]-->  
....
</head>

また、それに合わせてIE の最新の仕様(IE=edge)でレンダリングされるように meta 要素に「http-equiv=”X-UA-Compatible”」を追加しておきます。

<meta http-equiv="X-UA-Compatible" content="IE=edge">

レイアウト

伸縮するレイアウト

モバイル用の Web ページを作成する場合、各領域の幅をパーセント(%)で指定するのが一般的です。

幅をピクセル(px)で指定することもできますが、モバイル端末の画面の幅(仮想ウィンドウサイズの幅)は、機種ごとに異なるため、調整が大変です。そのため、ページの幅を width: 100% のようにパーセントで指定し、それに合わせて内部のコンテンツの幅もパーセントで指定します。

画面サイズに応じてレイアウトを変化させるには、メディアクエリを利用して幅やフロート(回り込み)の値を変化させる方法がよく使われます。

各領域の幅をパーセントで指定する伸縮するレイアウトをリキッドレイアウト(Liquid Layout)やフルードレイアウト(Fluid Layout)と呼びます。

参考ページ:「伸縮する2カラムレイアウト

レイアウトの例

以下の例では、650px と 960px の2箇所にブレイクポイントを設定しています(ブレイクポイントの値は、適当な値です)。

  • Small:小画面用(スマートフォン 650px 以下)→1カラムの可変幅
  • Medium:中画面用(タブレットなど 651px~960px)→1カラムの可変幅
  • Large:大画面用(PC 961px 以上)→2カラムの可変幅(サイドバーの幅は固定)

画面幅による遷移

レスポンシブデザインのサンプル

以下の例では、小画面、中画面、大画面の関係がわかりやすいように、各領域ごとに解説しています。そのためメディアクエリの記述もばらばらになっていますが、実際のコーディングの際は、モバイルファーストの手法を使うほうが効率良く記述できます。(必ずしもメディアクエリをまとめる必要はないと思いますが)

head 要素内の記述

以下は head 要素内の記述です。レスポンシブに関連するのは、5行目の viewport の指定(及び 13行目~16行目)になります。

5行目:viewport の指定。
width=device-width:デバイスの横幅に合わせてコンテンツを表示
initial-scale=1:iPhone を縦から横に回転させた時に、ページが拡大表示されるのを防。

6行目:IE 対策(互換表示させない。スタイルシートやスクリプトタグなどより前に記述)

10行目:Google Font の読み込み

11行目:アイコンフォント(fontawesome)の読み込み
(※古いバージョン4.7でのCDN読み込み 2017年12月時点)

12行目:CSS の読み込み

13行目~16行目:古い IE への対応(必要に応じて指定)。全ての CSS ファイルの後に読み込みます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Responsive Web Design Sample 01</title>
<meta name="description" content="Responsive Web Design Sample">
<meta name="keywords" content="responsive,viewport,media queries,break point">
<link href="https://fonts.googleapis.com/css?family=Architects+Daughter" rel="stylesheet">
<script src="https://use.fontawesome.com/xxxxxxxx.js"></script>
<link rel="stylesheet" href="style.css">
<!--[if lt IE 9]>
<script src="html5shiv-printshiv.min.js"></script>
<script src="respond.min.js"></script>
<![endif]-->  
</head>   
HTML の構成

ヘッダー、メイン、サイドバー、フッターの領域から構成されています。

HTML の構成(ヘッダー、メイン、サイドバー、フッターの領域)

  • ヘッダー:header 要素で作成し、nav 要素でナビゲーションメニューを配置。
  • メイン:id="main" の div 要素で作成。
  • サイドバー:aside 要素で作成。中画面で2列に表示するため、2つの div 要素を配置。
  • フッター:footer 要素で作成。

「フッター」は、画面幅いっぱいに広げるので、それ以外を id="warpper" の div 要素で囲んでいます。

<body>
<div id="warpper"> 
  <!-- ========== HEADER ========== -->
  <header>
    <div id="header-top">
      <h1 id="top_title">Responsive Web Design</h1>
      <ul id="header-top-link">
        <li><a href="#"><i class="fa fa-envelope-o" aria-hidden="true"></i><br>
          <span>Contact</span></a></li>
        <li><a href="#"><i class="fa fa-user-circle-o" aria-hidden="true"></i><br>
          <span>Log in</span></a></li>
      </ul> 
    </div>
    <div id="header-img"></div>
    <nav> 
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">News</a></li>
        <li><a href="#">Photo</a></li>
        <li><a href="#">Sample</a></li>
        <li><a href="#">FAQ</a></li>
        <li><a href="#">About</a></li>
      </ul> 
    </nav>
  </header>
  <!-- ========== MAIN ========== -->
  <div id="main">
    <section>
      <h1 class="title">Viewport</h1>
      <p class="main-text">Lorem ipsum dolor sit amet...</p>
      <div class="row">
        <div class="col-3-3-1"><img src="images/img1-01.jpg" alt="">
          <p class="text-center">sample</p>
        </div>
        <div class="col-3-3-1"><img src="images/img1-02.jpg" alt="">
          <p class="text-center">sample</p>
        </div>
        <div class="col-3-3-1"><img src="images/img1-03.jpg" alt="">
          <p class="text-center">sample</p>
        </div>
      </div>
    </section>
    <section>
      <h1 class="title">Media Queries</h1>
      <p class="main-text">Animi sint corrupti ipsum...</p>
      <section>
        <div class="row">
          <div class="col-2-2-1-60">
            <h2 class="title">Break Point</h2>
            <p class="main-text">Vitae, nam, aperiam...</p>
            <p class="main-text">Possimus, error, a id...</p>
          </div>
          <img class="col-2-2-1-40" src="images/img2-01.jpg" alt=""> 
        </div>
      </section>
      <section>
        <h2 class="title">Grid System</h2>
        <p class="main-text">Sapiente dolorum impedit...</p>
        <div class="row"> 
          <img src="images/img3-01.jpg" class="col-4-2-2 sm-nopad" alt=""> 
          <img src="images/img3-02.jpg" class="col-4-2-2 sm-nopad" alt=""> 
          <img src="images/img3-03.jpg" class="col-4-2-2 sm-nopad" alt=""> 
          <img src="images/img3-04.jpg" class="col-4-2-2 sm-nopad" alt=""> 
        </div>
      </section>
    </section>
  </div>
  <!-- ========== SIDE BAR ========== -->
  <aside>
    <div id="sidebar1">
      <div class="banner"><img src="http://via.placeholder.com/300x200/" alt="" /></div>
      ・・・中略・・・
      <div class="banner"><img src="http://via.placeholder.com/300x100/" alt="" /></div>
    </div>
    <div id="sidebar2">
      <div class="banner"><img src="http://via.placeholder.com/300x180/" alt="" /></div>
      ・・・中略・・・
      <p>Nobis, dicta dolore porro ab et! ... </p>
    </div>
  </aside>
</div><!-- end of #warpper -->
<!-- ========== FOOTER ========== -->
<footer>
  <div class="footer_content"> 
    <ul>
      <li><a href="#">Home</a></li>
      ・・・中略・・・
      <li><a href="#">Contact</a></li>
      <li><a href="#">Log in</a></li>
    </ul>
    <p id="copyright"><small>Copyright (C) 2017 Web Design Leaves </small><br>
      All rights reserved.</p>
  </div>
</footer>
</body>
CSS の初期化(簡易リセット)

CSS の先頭で、簡易的なリセットと box-sizing プロパティ、img 要素のスタイルを指定しています。

最初にブラウザごとの差異を解消するために全ての要素の margin と padding を 0 に設定しています(3~4行目)。実際には Reset CSS や Normalize.css などを利用することが多いかと思います。

そして box-sizing プロパティの値を border-box に指定しています(5~6行目)。この指定によりボックスのサイズをパディングとボーダーを含めたサイズで指定できるので、サイズ指定の計算が簡単になります。

続いて Windows Phone と iPhone でデバイスの向きを変えた後にユーザーの文字サイズが自動調整されるのを防止する設定をしています(10~11行目)。これらのプロパティは、文字サイズの自動調整を指定するプロパティで、値に 100% を指定すると自動調整が無効になり、CSS で指定したサイズで文字が表示されます。

最後に親要素の幅に合わせて画像を表示するように img 要素に max-width: 100% と height: auto を指定しています。display: block を指定することにより、img 要素をブロック要素で囲まなくても済むようにしています。

@charset "utf-8";
* {
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box; 
}

html {
  -ms-text-size-adjust: 100%;  /* IE on Windows Phone用 */
  -webkit-text-size-adjust: 100%;  /* iOS用 */
  font-family: Tahoma, Geneva, sans-serif;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}
CSS レイアウトの変化
id="warpper" の div 要素

全体(フッターを除く)の幅を制御するために、id="warpper" の div 要素に width:100%(小画面、中画面)を指定しています。

画面の幅が 961px 以上の大画面では、必要以上に広がらないように最大幅 max-width: 1160px を指定して、 1160px より広がらないようにしています。

左右にパディングを 15px 指定して、box-sizing: border-box を指定しているのでコンテンツの幅は最大 1130px (1160 - 15 x 2) になります。

また、左右のマージンに auto を指定してコンテンツを中央寄せで表示するようにしています。

#warpper { /* 小画面、中画面 */
  width: 100%;
}
@media only screen and (min-width:961px) { /* 大画面 */
  #warpper {
    max-width: 1160px;
    padding: 0px 15px;
    margin: 0px auto;
  }
}
<body>
<div id="warpper"> 
  <!-- ========== HEADER ========== -->
  <header>
    ・・・中略・・・
  </header>
  <!-- ========== MAIN ========== -->
  <div id="main">
    ・・・中略・・・
  </div> 
  <!-- ========== SIDE BAR ========== -->
  <aside>
    ・・・中略・・・
  </aside>
</div><!-- end of #warpper -->
<!-- ========== FOOTER ========== -->
<footer>
  ・・・中略・・・
</footer>
</body>
ヘッダー

以下はヘッダー領域の header 要素のスタイルで、全てのレイアウトで共通になります。

header 要素の親要素は id="warpper" の div 要素となっていて、小画面、中画面では画面幅いっぱいにヘッダーが表示されます。大画面では id="warpper" の div 要素の幅に追従し、最大で 1160px となり、左右に 15px の余白(パディング)ができます。

header { /* 全レイアウトで共通 */
  width: 100%;
}
メイン

メイン領域は id="main" の div 要素で、以下のスタイルを指定しています。

小画面、中画面のレイアウトでは幅100%でメイン領域が表示されます。上下のマージン及び左右のパディング(15px)を指定しています。左右のパディングは小画面、中画面で見た目を良くするために指定しています。

大画面のレイアウトでは幅を指定していませんが、この場合、小画面、中画面で指定した幅100%を継承します。margin-right: -300px と padding-right: 330px を指定してサイドバーの領域(300px)を確保しています。(詳細は伸縮する2カラムレイアウトを参照ください。)

また、小画面、中画面のレイアウトで左右のパディング(15px)を指定しているので、大画面では左側がヘッダーの幅に揃うようにネガティブマージン(margin-left: -15px)を指定しています。

#main { /* 小画面、中画面 */
  width: 100%;
  margin: 40px 0px;
  padding: 0px 15px;
}
@media only screen and (min-width:961px) { /* 大画面 */
  #main {
    margin-left: -15px;
    float: left;
    margin-right: -300px;
    padding-right: 330px;
  }
}
サイドバー

このサンプルでは、サイドバーの幅を 300px に固定しています。小画面のレイアウトでは aside 要素の幅を 300px に指定して、左右のマージンに auto を指定して中央寄せにしています。

また、小画面のレイアウトではサイドバーの内容が長すぎないように一部非表示にするために、コンテンツを id 属性が #sidebar1 と #sidebar2 の2つの div 要素で構成し、#sidebar2 に display: none を指定して非表示にしています。

中画面のレイアウトではサイドバーを2列に配置しています。そのため aside 要素の幅を 620px に指定して #sidebar1 と #sidebar2 の幅を 300px に指定し、float で左右に配置しています。#sidebar1 と #sidebar2 の間には 20px (620 - 300 x 2) の間隔ができます。

また、小画面のレイアウトで #sidebar2 に display: none を指定して表示にしているので、中画面のレイアウトで表示するために、display: block を指定しています。

大画面のレイアウトでは、aside 要素の幅を 300px に指定し、float: right で右寄せにしています。#sidebar2 の非表示の解除は、すでに中画面で display: block を指定しているので不要です(中画面の設定は 651px 以上なので、大画面にも継承されます)。

また、中画面のレイアウトで指定した #sidebar1 と #sidebar2 の float の指定も継承されますが、親要素の aside 要素の幅が 300px しかないのでフロートされることはないので、float を解除しなくても大丈夫です。

28行目~32行目の指定は、clearfix の指定です。aside 要素内に配置された #sidebar1 と #sidebar2 の div 要素には float が指定されているので、この指定をしないと aside 要素の高さが正しく認識されません。

aside { /* 小画面 */
  width: 300px;
  margin: 40px auto;
}
#sidebar2 {
  display: none;
}
@media only screen and (min-width:651px) { /* 中画面 */
  aside {
    width: 620px;
  }
  #sidebar1 {
    width: 300px;
    float: left;
  }
  #sidebar2 {
    width: 300px;
    float: right;
    display: block;
  }
}
@media only screen and (min-width:961px) { /* 大画面 */
  aside {
    width: 300px;
    float: right;
  }
}
aside:after { /* clearfix */
  display: table;
  content: "";
  clear: both;
}
<!-- ========== SIDE BAR ========== -->
<aside>
  <div id="sidebar1">
    <div class="banner"><img src="http://via.placeholder.com/300x200/" alt="" /></div>
    ・・・中略・・・
    <div class="banner"><img src="http://via.placeholder.com/300x100/" alt="" /></div>
  </div>
  <div id="sidebar2">
    <div class="banner"><img src="http://via.placeholder.com/300x180/" alt="" /></div>
    ・・・中略・・・
    <p>Nobis, dicta dolore porro ab et! ... </p>
  </div>
</aside>
</div><!-- end of #warpper -->
各領域の CSS
ヘッダー

ヘッダーの上部に「サイトのタイトル」とコンタクト及びログインの「リンク」を配置しています。id 属性が header-top の div 要素がこの部分になります。

「サイトのタイトル」は h1 要素で作成しています。フォントには Google Fonts を利用しています。

コンタクト及びログインの「リンク」は ul 要素を使ってマークアップしています。それぞれの li 要素には、リンクを指定する a 要素、アイコンを表示する i 要素(Font Awesome アイコンフォント) 、文字を表示する span 要素が入っています。

文字を span 要素でマークアップしているのは、画面サイズにより文字を表示・非表示にするためです。

<div id="warpper"> 
  <!-- ========== HEADER ========== -->
  <header>
    <div id="header-top">
      <h1 id="top_title">Responsive Web Design</h1>
      <ul id="header-top-link">
        <li><a href="#"><i class="fa fa-envelope-o" aria-hidden="true"></i><br>
          <span>Contact</span></a></li>
        <li><a href="#"><i class="fa fa-user-circle-o" aria-hidden="true"></i><br>
          <span>Log in</span></a></li>
      </ul> 
    </div>
    <div id="header-img"></div>
    <nav> 
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">News</a></li>
        <li><a href="#">Photo</a></li>
        <li><a href="#">Sample</a></li>
        <li><a href="#">FAQ</a></li>
        <li><a href="#">About</a></li>
      </ul> 
    </nav>
  </header>
  <!-- ========== MAIN ========== -->
  <div id="main">    

サイトのタイトル(id="top_title" の h1 要素)には以下のスタイルが指定されています。

フォントの指定(この例では Google Fonts を利用)、左寄せ(float: left)、マージン、フォントサイズを指定しています。

フォントサイズは、小画面では 18px, 中画面及び大画面では 32px に指定しています。また、フォントサイズがちょうどいい大きさに表示されるように、マイナーブレークポイントを設定して、画面幅が401px ~ 650px の場合は、24px で表示するようにしています。

#top_title {  /* 小画面 */
  font-family: 'Architects Daughter', cursive;
  float: left;
  margin: 15px 0px 3px 10px;
  font-size: 18px;
  color: #777;
}
@media only screen and (min-width:401px) {  /* マイナーブレークポイント */
  #top_title {
    font-size: 24px;
  }
}
@media only screen and (min-width:651px) {  /* 中画面、大画面 */
  #top_title {
    font-size: 32px;
  }
}

コンタクト及びログインのリンクは、id="header-top-link" の ul 要素でマークアップしています。以下がスタイルの設定です。

1~5行目は ul 要素のスタイルで、右寄せ(float: right)、マージン、マーカーなし(list-style-type:none)を指定しています。

6~9行目は li 要素のスタイルで、display: inline-block を指定して横並びにし、margin-left で間隔を調整しています。

10~14行目は a 要素のスタイルで、display: block でブロックレベル要素にすることで、テキスト以外の部分、余白の部分(文字の周囲)もクリックできるようになります。

15~18行目はアイコンフォントを表示する i 要素のスタイルで、アイコンフォントのフォントサイズと垂直方向の位置(vertical-align: -12px)を指定しています。

19~21行目は小画面での文字(Contact, Log in)の部分の設定です。小画面では画面幅が狭いのでアイコンのみを表示(文字を非表示)するように、display: none を指定しています。

22~31行目は中画面、大画面での文字の部分の設定で、文字をインラインで表示するように display: inline を指定し、色とフォントサイズも指定しています。また、アイコンフォントの垂直位置をデフォルトの baseline に指定しています。

32~36行目は clearfix の指定です。

#header-top-link {
  float: right;
  margin: 10px 10px 5px;
  list-style-type: none;
}
#header-top-link li {
  display: inline-block;
  margin-left: 10px;
}
#header-top-link a {
  display: block;
  text-decoration: none;
  color: #999;
}
#header-top-link i {
  font-size: 22px;
  vertical-align: -12px;
}
#header-top-link span {
  display: none;
}
@media only screen and (min-width:651px) {
  #header-top-link span {
    display: inline;
    color: #666;
    font-size: 15px;
  }
  #header-top-link i {
    vertical-align: baseline;
  }
}
#header-top:after {
  display: table;
  content: "";
  clear: both;
}
ヘッダー画像

この例では、id="header-img" の div 要素に背景画像を指定してヘッダー画像を表示しています。

<header>
  <div id="header-top">
    <h1 id="top_title">Responsive Web Design</h1>
    <ul id="header-top-link">
      ....
    </ul> 
  </div>
  <div id="header-img"></div> <!-- 背景画像でヘッダー画像を表示-->
  <nav> 
    <ul>
      <li><a href="#">Home</a></li>
      ...
    </ul> 
  </nav>
</header>

この例では、1200px X 360px の画像を使用しています。ページの最大幅は max-width: 1160px と指定しているのと、以下のスタイル指定で大画面の場合の背景画像の高さを 300px と指定しているので、実際には 1160px X 300px の比率の画像を用意した方が使いやすいかもしれません。

以下がスタイルの指定です。

div 要素に高さ(小画面の場合 height: 200px)を指定し、background-image で背景画像を指定しています。

background-size に cover を指定して、全体を覆うように配置しています。cover を指定すると、背景画像の表示サイズが背景の表示領域全体をカバーするサイズに自動調整されます。 (背景画像の縦横比は維持されるので、「背景画像の縦横比」と「描画領域の縦横比」が一致しない場合は、背景画像の一部が切り取られます。)

また、この例では、background-position に bottom(center bottom)を指定しています。キーワードの指定が1つの場合、省略した値は center になります。

ポジションの指定の違いはサンプルのポジションのプルダウンで確認できます(ウィンドウ幅を狭めて試すと違いがわかりやすいです)。ヘッダー画像の表示される範囲は画面サイズに応じて変化します。どのような画面サイズでもうまくヘッダー画像を表示させるには、画像の内容やそのポジションに工夫が必要になります。

中画面、大画面では id="header-img" の div 要素の高さを変更することにより、画像の表示領域の高さが変化します。(8行目~18行目)

それぞれの画面サイズでの高さは、写真やデザインによって適切なサイズを決めます。全ての画面サイズで同じ比率にする必要はなく、逆に同じ比率にすると小画面のレイアウトでは、画像が小さくなりすぎる可能性が高いです(背景画像ではなく、img 要素を使う例)。

#header-img {  /* 小画面 */
  height: 200px;
  background-image: url("images/header-img.jpg");
  background-size: cover;
  background-position: bottom;
}

@media only screen and (min-width:651px) {  /* 中画面 */
  #header-img {
    height: 250px;
  }
}

@media only screen and (min-width:961px) {  /* 大画面 */
  #header-img {
    height: 300px;
  }
}

画面サイズにより背景画像を変更する例

画面サイズに応じて画像ファイルを切り替える場合、小画面、中画面、大画面用の画像ファイルを用意します。モバイル端末の通信環境は PC に比べて一般的に速くないので、可能であれば軽い画像を使ったほうがユーザーの負担を軽減できます。(但し、解像度を考慮するとあまり小さくもできませんが)

以下の例では、header-img1_S.jpg(小画面用)、header-img1_M.jpg(中画面用)、header-img1_L.jpg(大画面用)の3つの画像ファイルを用意して、メディアクエリを使って画像の高さと画像ファイルを変更しています。

また、この例では最大画面幅での画像表示領域のサイズ(1160px X 300px)の比率の画像を使用しています。デザインや写真によっては、それぞれの画面サイズで異なる縦横比の画像を使用することもできます。

#header-img {  /* 小画面 */
  height: 200px;
  background-image: url("images/header-img1_S.jpg");
  background-size: cover;
  background-position: bottom;
}

@media only screen and (min-width:651px) {  /* 中画面 */
  #header-img {
    height: 250px;
    background-image: url("images/header-img1_M.jpg");
  }
}

@media only screen and (min-width:961px) {  /* 大画面 */
  #header-img {
    height: 300px;
    background-image: url("images/header-img1_L.jpg");
  }
}

レスポンシブデザインのサンプル2

背景画像ではなく、img 要素を使う例

以下はヘッダー画像を背景画像ではなく、img 要素を使って表示する場合の例です。この場合は、img 要素の幅に 100% を指定するだけ、スタイルの指定はとても単純です。

但し、画像の縦横比を維持したまま変化していくので、小画面のレイアウトでは、画像が小さくなりすぎてしまう場合が多いです。picture 要素を使えば、画像を切り替えることができますが、IE はサポートしていません。

<div id="header-img"><img src="images/header-img.jpg" alt="ヘッダ画像"></div>
#header-img img {
  width: 100%;
}

レスポンシブデザインのサンプル3

ナビゲーションメニュー

この例のナビゲーションメニューは以下のようなマークアップになっています。ul 要素を使用して、メニュー項目を li 要素で作成しています。

<div id="warpper"> 
  <header>
    <div id="header-top">
      ・・・中略・・・
    </div>
    <div id="header-img"></div>
    <!-- ========== NAV ========== -->
    <nav> 
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">News</a></li>
        <li><a href="#">Photo</a></li>
        <li><a href="#">Sample</a></li>
        <li><a href="#">FAQ</a></li>
        <li><a href="#">About</a></li>
      </ul> 
    </nav>
  </header> 

以下がスタイルの指定です。

4行目~11行目は小画面での li 要素のスタイルの指定で、メニューの各項目を2列で表示するため、幅を50%に指定して左寄せ(float: left)の配置に指定ます。7行目はメニュー項目下部の境界線(ボーダー)の指定です。

10行目は :nth-child() 疑似クラスを使って奇数番目のメニュー項目に右側の境界線を指定して中央に線を表示しています。

13行目~22行目は中画面・大画面でのレイアウトで、各項目を16.66666667%(100/6)の幅に指定して横一列に表示しています。また、全ての項目の右側に境界線を表示するため border-right: solid 2px #355B8E で右側の境界線のスタイルを上書きしています。更に border-bottom: none を指定して下部の境界線をなしにしています。

19行目~21行目は :last-child 疑似クラスを使って最後の項目(li 要素)の右の境界線をなしにしています。

小画面・中画面でのメニュー項目

nav ul {
  list-style-type: none; /* マーカーなしを指定 */
}
nav li {
  width: 50%;
  float: left;
  border-bottom: solid 2px #355B8E;
}
nav li:nth-child(odd) {
  border-right: solid 2px #355B8E;
}

@media only screen and (min-width:651px) { /* 中画面、大画面 */
  nav li {
    width: 16.66666667%;
    border-right: solid 2px #355B8E;
    border-bottom: none;
  }
  nav li:last-child {
    border-right: none;
  }
}

nav a {
  display: block;
  background: #030D2E;
  color: #FFF;
  font-weight: bold;
  font-size: 13px;
  line-height: 48px;
  padding-left: 15px;
  text-decoration: none;
}

@media only screen and (min-width:651px) { /* 中画面、大画面 */
  nav a {
    line-height: 36px;
    text-align: center;
    padding-left: 0;
  }
}

nav a:hover {
  background: #3B6FB5;
  text-decoration: underline;
}
nav ul:after {
  display: table;
  content: "";
  clear: both;
}

24行目~33行目はリンク(a 要素)のスタイルの指定です。display: block で a 要素をブロックレベル要素に変更してリンクの範囲を拡張しています。続いてリンクの背景色、文字色、フォントのスタイルを指定しています(これらのスタイルは全てのレイアウトで共通です)。

30行目はメニュー項目の高さを line-height: 48px で指定しています。スマートフォンなど指で操作するデバイスでは、タップターゲットの最小サイズは48px前後が推奨されています。この例では縦方向のリンクが隣接しているので(間違ってリンクをタップしないように)高さを 48px に指定しています。(幅は 50% あるので十分なサイズがあります)

35行目~41行目は中画面・大画面でのレイアウトです。メニュー項目が横一列に並ぶため隣接するリンクとの間は十分な間隔があるのと見た目を考慮して高さを36pxに変更し、文字を中央揃えに指定しています。また、31行目で指定した padding-left: 15px を 0 に変更しています。

43行目~46行目は、マウスオーバー(ホバー)時の背景色の指定です。

47行目~51行目は、li 要素に指定した float に対する clearfix の指定です。

サイドバー

以下がサイドバーのマークアップです。

レスポンシブに関する設定は、「CSS レイアウトの変化」のサイドバーの設定で完了しています。

<!-- ========== SIDE BAR ========== -->
  <aside>
    <div id="sidebar1">
      <div class="banner"><img src="http://via.placeholder.com/300x200/" alt="" /></div>
      ・・・中略・・・
      <div class="banner"><img src="http://via.placeholder.com/300x100/" alt="" /></div>
    </div>
    <div id="sidebar2">
      <div class="banner"><img src="http://via.placeholder.com/300x180/" alt="" /></div>
      ・・・中略・・・
      <p>Nobis, dicta dolore porro ab et! ... </p>
    </div>
  </aside>
</div><!-- end of #warpper -->

バナーのダミーコンテンツのスタイルは以下を指定しています。

.banner {
  margin-bottom: 15px;
  text-align: center;
  font-size: 14px;
}
aside p {
  font-size: 14px;
  line-height: 1.3;
  margin-bottom: 10px;
}
メイン

以下がメインのマークアップです。各記事を section 要素で区切り、見出しを配置しています。

<div id="main">
  <section>
    <h1 class="title">Viewport</h1>
    <p class="main-text">Lorem ipsum dolor sit amet...</p>
    <div class="row">
      <div class="col-3-3-1"><img src="images/img1-01.jpg" alt="">
        <p class="text-center">sample</p>
      </div>
      <div class="col-3-3-1"><img src="images/img1-02.jpg" alt="">
        <p class="text-center">sample</p>
      </div>
      <div class="col-3-3-1"><img src="images/img1-03.jpg" alt="">
        <p class="text-center">sample</p>
      </div>
    </div><!-- end of .row -->
  </section>
  <section>
    <h1 class="title">Media Queries</h1>
    <p class="main-text">Animi sint corrupti ipsum...</p>
    <section>
      <div class="row">
        <div class="col-2-2-1-60">
          <h2 class="title">Break Point</h2>
          <p class="main-text">Vitae, nam, aperiam...</p>
          <p class="main-text">Possimus, error, a id...</p>
        </div>
        <img class="col-2-2-1-40" src="images/img2-01.jpg" alt=""> 
      </div><!-- end of .row -->
    </section>
    <section>
      <h2 class="title">Grid System</h2>
      <p class="main-text">Sapiente dolorum impedit...</p>
      <div class="row"> 
        <img src="images/img3-01.jpg" class="col-4-2-2 sm-nopad" alt=""> 
        <img src="images/img3-02.jpg" class="col-4-2-2 sm-nopad" alt=""> 
        <img src="images/img3-03.jpg" class="col-4-2-2 sm-nopad" alt=""> 
        <img src="images/img3-04.jpg" class="col-4-2-2 sm-nopad" alt=""> 
      </div><!-- end of .row -->
    </section>
  </section>
</div>

外側の section 要素には margin-bottom: 60px を指定し、内側の section 要素には margin-top: 40px; を指定して間隔を取っています。(色々な方法があると思います)

#main section {
  margin-bottom: 60px;
}
#main section section{
  margin-top: 40px;
}

文字サイズの指定

スマートフォンで閲覧する際は、PC やタブレットに比べて画面と顔の距離が近くなるため小さい文字でも視認できることや幅の狭い画面で大きな文字を表示すると、一行あたりの文字が減り、読みにくくなってしまいます。

そのため小画面のレイアウトの文字を小さめに指定します。

この例では文字サイズの指定を以下のようにしています。小画面では見出しのサイズを h1 要素:20px、h2 要素:18px に指定し、中画面・大画面では h1 要素:24px、h2 要素:20px に指定しています。

本文の p 要素も同様に、小画面では 15px に指定し、中画面・大画面では 16px に指定しています。(これらのサイズは一例ですので、実際にはサイトの内容やデザインに合わせて設定します。)

h1.title, h2.title {  /* 小画面 */
  color: #333;
  line-height: 1.2;
  border-bottom: solid 1px #999;
  margin-bottom: 8px;
}
h1.title {
  font-size: 20px;
}
h2.title {
  font-size: 18px;
}
@media only screen and (min-width:651px) { /* 中画面&大画面 */
  h1.title {
    font-size: 24px;
  }
  h2.title {
    font-size: 20px;
  }
}

.main-text {  /* 小画面 */
  font-size: 15px;
  line-height: 1.5;
}
@media only screen and (min-width:651px) { /* 中画面&大画面 */
  .main-text {
    font-size: 16px;
  }
}

コンテンツのレイアウト

この例では、メインのコンテンツは小画面や中画面の場合、1段組または2段組のレイアウトで構成し、大画面の場合は4段組、3段組、2段組のレイアウトで構成しています。

それぞれの領域には、画像を含んでいるので画像が親要素の大きさに合わせて伸縮するように、以下の設定を「CSS の初期化(簡易リセット)」で指定しています。

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

レイアウトが変化する領域の HTML を抜粋すると以下のようになっています。この例では大画面で1行に表示される領域に row と言うクラスを指定しています。

このようなレイアウトの変化はコンテンツにより様々に変化する可能性があるので、グリッドシステムを利用する方が色々なパターンに簡単に対応できるので便利ですが、この例ではグリッドシステムは使用せずにスタイルを指定しています。

また、レイアウトが変化する div 要素には以下のようなクラスを指定しています。(もっと良い名前の付け方があると思いますが)

  • col-3-3-1:大画面及び中画面では3列、小画面では1列で表示
  • col-2-2-1-60:大画面及び中画面では2列で60%の幅、小画面では1列で表示
  • col-2-2-1-40:大画面及び中画面では2列で40%の幅、小画面では1列で表示
  • col-4-2-2:大画面では4列、中画面及び小画面では2列で表示
<div id="main">
・・・
  <div class="row">
    <div class="col-3-3-1"><img src="images/img1-01.jpg" alt="">
      <p class="text-center">sample</p>
    </div>
    <div class="col-3-3-1"><img src="images/img1-02.jpg" alt="">
      <p class="text-center">sample</p>
    </div>
    <div class="col-3-3-1"><img src="images/img1-03.jpg" alt="">
      <p class="text-center">sample</p>
    </div>
  </div><!-- end of .row -->
・・・
  <div class="row">
    <div class="col-2-2-1-60">
      <h2 class="title">Break Point</h2>
      <p class="main-text">Vitae, nam, aperiam...</p>
      <p class="main-text">Possimus, error, a id...</p>
    </div>
    <img class="col-2-2-1-40" src="images/img2-01.jpg" alt=""> 
  </div><!-- end of .row -->
・・・
  <div class="row"> 
    <img src="images/img3-01.jpg" class="col-4-2-2 sm-nopad" alt=""> 
    <img src="images/img3-02.jpg" class="col-4-2-2 sm-nopad" alt=""> 
    <img src="images/img3-03.jpg" class="col-4-2-2 sm-nopad" alt=""> 
    <img src="images/img3-04.jpg" class="col-4-2-2 sm-nopad" alt=""> 
  </div><!-- end of .row -->
・・・
</div><!-- end of #main -->

以下のようなスタイルを指定しています。

.row ではマージンの調整と clearfix を指定しています。左右のネガティブマージン(-15px)は、その中の div 要素に左右のパディング(15px)を指定しているのでその調整です。clearfix はその中の div 要素にフロートを指定しているためです。

小画面ででは、.col-2-2-1-60, .col-2-2-1-40, .col-3-3-1 の各クラスは1段組で表示するので幅を 100% に指定し、.col-4-2-2 は2段組で表示するので幅を50%に指定しています。

.col-4-2-2 は直接 img 要素に指定していますが、すでに画像のスタイルで display: block; を指定してブロックレベル要素に変換しているので、追加で指定する必要はありません。

また、float: left で右寄せにしています(小画面では右寄せにする必要はありませんが、中画面及び大画面で右寄せにするのでここでまとめて指定しています)。

中画面及び大画面では、.col-3-3-1 は3段組なので幅を 33.33333333% に、.col-4-2-2 は4段組なので幅を 25% に指定しています。

.col-2-2-1-60 と .col-2-2-1-40 は2段組ですが、それぞれの幅を 60% と 40% に指定しています。

margin-top: 0 はマージンの調整です。小画面では1段組なので、上下の余白のために margin-top: 20px を指定していますが、中画面及び大画面ではその余白が不要なので margin-top: 0 を指定しています。

.row {  /* 全画面共通 */
  margin: 10px -15px;
}
.row:after {
  display: table;
  content: "";
  clear: both;
}

.col-2-2-1-60, .col-2-2-1-40, .col-3-3-1 {  /* 小画面 */
  width: 100%;
  padding: 0px 15px;
  float: left;
  margin-top: 20px;
}
.col-4-2-2 {  /* 小画面 */
  width: 50%;
  padding: 0px 15px;
  float: left;
}

@media only screen and (min-width:651px) { /* 中画面&大画面 */
  .col-3-3-1 {
    width: 33.33333333%;
    margin-top: 0;
  }
  .col-4-2-2 {
    width: 25%;
  }
  .col-2-2-1-60 {
    width: 60%;
    margin-top: 0;
  }
  .col-2-2-1-40 {
    width: 40%;
    margin-top: 0;
  }
}

グリッドシステム

グリッドシステムとは、レイアウトを格子状(グリッド/Grid)に分割してコンテンツを配置するデザイン手法です。多くのグリッドシステムでは、全体を12列に分割する構成で作成されています。

12と言う数字は、2でも、3でも、4でも割り切れる便利な数字のため、領域を2等分、3等分、4等分するレイアウトに簡単に対応できます。また、3列-9列、5列-7列のようなレイアウトを作成することができます。

グリッドシステムを利用する場合、簡単なのは Bootstrap などの CSS フレームワークを利用する方法です。(参考:Bootstrap3 グリッドシステムBootstrap4 グリッドシステム

以下は、単純な12分割のグリッドシステムの例です。

ユニバーサルセレクタで、box-sizing: border-box を全ての要素に設定しています。グリッドの行は、.row で囲みます(パディングの調整及び cleafix )。

この例では、sm-n(小画面用), md-n(中画面用), lg-n(大画面用)というクラス名(n は1~12 の数値)を使って各ブロックの幅を指定します。

例えば、sm-6 を指定した場合、その要素は6列分の幅で表示され、sm-4 を指定すれば4列分の幅で表示されます。

sm-n は画面幅が 1px 以上、md-n は画面幅が 651px 以上、lg-n は画面幅が 961px 以上に対応するクラスです。

12分割グリッドの例

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
*:before, *:after {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
.container {
  max-width: 1160px;
  padding: 0 15px;
  margin: 0 auto;
}
.row {
  margin: 0 -15px;
}
.row:before, .row:after {
  display: table;
  content: " ";
}
.row:after {
  clear: both;
}
.sm-1, .md-1, .lg-1, 
.sm-2, .md-2, .lg-2, 
.sm-3, .md-3, .lg-3, 
.sm-4, .md-4, .lg-4, 
.sm-5, .md-5, .lg-5, 
.sm-6, .md-6, .lg-6, 
.sm-7, .md-7, .lg-7, 
.sm-8, .md-8, .lg-8, 
.sm-9, .md-9, .lg-9, 
.sm-10, .md-10, .lg-10, 
.sm-11, .md-11, .lg-11, 
.sm-12, .md-12, .lg-12 {
  position: relative;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}
.sm-1,.sm-2,.sm-3,.sm-4,.sm-5,.sm-6,.sm-7,.sm-8,.sm-9,.sm-10,.sm-11,.sm-12 {
  float: left;
}
.sm-12 {
  width: 100%;
}
.sm-11 {
  width: 91.66666667%;
}
.sm-10 {
  width: 83.33333333%;
}
.sm-9 {
  width: 75%;
}
.sm-8 {
  width: 66.66666667%;
}
.sm-7 {
  width: 58.33333333%;
}
.sm-6 {
  width: 50%;
}
.sm-5 {
  width: 41.66666667%;
}
.sm-4 {
  width: 33.33333333%;
}
.sm-3 {
  width: 25%;
}
.sm-2 {
  width: 16.66666667%;
}
.sm-1 {
  width: 8.33333333%;
}

@media (max-width: 420px) {
  .sm-1 { /* パディングが大きくなりすぎて段落ちするので調整 */
    padding-right: 10px;
    padding-left: 10px;
  }
}

@media (min-width: 651px) {
  .md-1,.md-2,.md-3,.md-4,.md-5,.md-6,.md-7,.md-8,.md-9,.md-10,.md-11,.md-12 {
    float: left;
  }
  .md-12 {
    width: 100%;
  }
  .md-11 {
    width: 91.66666667%;
  }
  .md-10 {
    width: 83.33333333%;
  }
  .md-9 {
    width: 75%;
  }
  .md-8 {
    width: 66.66666667%;
  }
  .md-7 {
    width: 58.33333333%;
  }
  .md-6 {
    width: 50%;
  }
  .md-5 {
    width: 41.66666667%;
  }
  .md-4 {
    width: 33.33333333%;
  }
  .md-3 {
    width: 25%;
  }
  .md-2 {
    width: 16.66666667%;
  }
  .md-1 {
    width: 8.33333333%;
  }
}

@media (min-width: 961px) {
  .lg-1,.lg-2,.lg-3,.lg-4,.lg-5,.lg-6,.lg-7,.lg-8,.lg-9,.lg-10,.lg-11,.lg-12 {
    float: left;
  }
  .lg-12 {
    width: 100%;
  }
  .lg-11 {
    width: 91.66666667%;
  }
  .lg-10 {
    width: 83.33333333%;
  }
  .lg-9 {
    width: 75%;
  }
  .lg-8 {
    width: 66.66666667%;
  }
  .lg-7 {
    width: 58.33333333%;
  }
  .lg-6 {
    width: 50%;
  }
  .lg-5 {
    width: 41.66666667%;
  }
  .lg-4 {
    width: 33.33333333%;
  }
  .lg-3 {
    width: 25%;
  }
  .lg-2 {
    width: 16.66666667%;
  }
  .lg-1 {
    width: 8.33333333%;
  }
}

以下は、
650px以下で閲覧すると各コンテンツ(div 要素)を12列(全体の幅 sm-12)で表示
651px以上で閲覧すると各コンテンツ(div 要素)を6列(全体の幅の50% md-6)で表示
961px以上で閲覧すると各コンテンツ(div 要素)を3列(全体の幅の25% lg-3)で表示する例です。

それぞれの画面幅において、対応するクラスの数値(n の部分)の合計が12になるように記述します。

グリッドシステムの例

<body>
<div class="container">
  <div class="row">
    <h1>Simple Grid System Sample 2</h1>
  </div>
  <div class="row">
    <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3 </div>
    <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3 </div>
    <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3 </div>
    <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3 </div>
  </div>
</div>
</body>

以下はグリッドをネスト(入れ子)した例です。ネストするには、親のカラムの中に新たに row クラスを追加して、その中にカラムを配置します。

グリッドシステム(ネスト)の例

<body>
<div class="container">
  <div class="row">
    <div class="md-8 lg-9"> Main
      <div class="row">
        <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3</div>
        <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3</div>
        <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3</div>
        <div class="sm-12 md-6 lg-3">sm-12 md-6 lg-3</div>
      </div>
    </div>
    <div class="md-4 lg-3"> Side 
      <div class="row">
        <div class="sm-12 side">md-4 lg-3</div>
      </div>
    </div>
  </div>
</div>
</body>

以下は、前述の「メインのコンテンツのレイアウト」をグリッドシステムを使って設定する例です。

<div class="sm-12 md-4 sm-mt-20">

  • 650px以下で閲覧するとを12列(全体の幅 sm-12 100%)で表示
  • 651px以上で閲覧すると4列(全体の幅の33.33333333% md-4)で表示
  • sm-mt-20 は650px以下でマージン(margin-top: 20px;)を設定するクラスで、651px 以上では margin-top: 0; を指定しています。

<div class="sm-12 md-7 sm-mt-20">

  • 650px以下で閲覧するとを12列(全体の幅 sm-12 100%)で表示
  • 651px以上で閲覧すると7列(全体の幅の58.33333333% md-7)で表示

<img class="sm-12 md-5 sm-mt-20" src="images/img2-01.jpg" alt="">

  • 650px以下で閲覧するとを12列(全体の幅 sm-12 100%)で表示
  • 651px以上で閲覧すると5列(全体の幅の41.66666667% md-5)で表示

<img src="images/img3-01.jpg" class="sm-6 md-3 sm-nopad" alt="">

  • 650px以下で閲覧するとを6列(全体の幅の50% sm-6)で表示
  • 651px以上で閲覧すると3列(全体の幅の25% md-3)で表示

<div id="main">
  <section>
    ・・・
    <div class="row">
      <div class="sm-12 md-4 sm-mt-20"><img src="images/img1-01.jpg" alt="">
        <p class="text-center">sample</p>
      </div>
      <div class="sm-12 md-4 sm-mt-20"><img src="images/img1-02.jpg" alt="">
        <p class="text-center">sample</p>
      </div>
      <div class="sm-12 md-4 sm-mt-20"><img src="images/img1-03.jpg" alt="">
        <p class="text-center">sample</p>
      </div>
    </div>
  </section>
  <section>
    ・・・
      <div class="row">
        <div class="sm-12 md-7 sm-mt-20">
          <h2 class="title">Break Point</h2>
          <p class="main-text">Vitae, nam, aperiam pariatur....</p>
          <p class="main-text">Possimus, error, a id totam ...</p>
        </div>
        <img class="sm-12 md-5 sm-mt-20" src="images/img2-01.jpg" alt=""> 
      </div>
    </section>
    <section>
      ・・・
    <div class="row">
        <img src="images/img3-01.jpg" class="sm-6 md-3 sm-nopad" alt=""> 
        <img src="images/img3-02.jpg" class="sm-6 md-3 sm-nopad" alt=""> 
        <img src="images/img3-03.jpg" class="sm-6 md-3 sm-nopad" alt=""> 
        <img src="images/img3-04.jpg" class="sm-6 md-3 sm-nopad" alt=""> 
      </div>

  </section>
</div> 

グリッドシステムを利用したレイアウトの例

参考サイト:
レスポンシブ対応のグリッド システムを実装する時に絶対覚えておきたいテクニック

要素の表示・非表示

画面サイズに応じてある部分(要素)を表示したり、表示しないというようなケースがあります。

前述のレイアウトの例では、小画面ではヘッダーのリンクをアイコンのみ表示し、中画面以上ではアイコンと文字を表示したり、小画面ではサイドバーの一部のコンテンツを非表示にしています。

これらの動作は、メディアクエリを使って画面サイズに応じて display の値を変更しています。

/* id header-top-link の span 要素の表示・非表示 */
#header-top-link span { /* 小画面 */
  display: none;
}
@media only screen and (min-width:651px) { /* 中画面&大画面 */
  #header-top-link span {
    display: inline;
    color: #666;
    font-size: 15px;
  }
}

/* id sidebar2 の div 要素の表示・非表示 */
#sidebar2 { /* 小画面 */
  display: none;
}
@media only screen and (min-width:651px) { /* 中画面&大画面 */
  #sidebar2 {
    display: block;
    width: 300px;
    float: right;
  }
}

個々の要素に上記のようにスタイルを設定することもできますが、画面幅に応じて要素の表示・非表示を制御するクラスを用意しておくと便利です。

画面サイズに応じて要素を非表示にするクラス

以下は、小画面のサイズ(650px以下)において指定した要素を非表示にするクラス(hide_small)の例です。

@media only screen and (max-width:650px) { /* 中画面&大画面 */
  .hide_small {
    display: none;
  }
}

以下のように、min-width を使って設定することもできますが、表示する際にその要素がブロック要素か、インライン要素か等 display の値が変わってくるので、クラスとして用意しておく場合は、前述のように max-width を使ったほうが汎用性が高くなります。

.hide_small_block { /* 小画面 */
  display: none;
}
@media only screen and (min-width:651px) { /* 中画面&大画面 */
  .hide_small_block {
    display: block;
  }
}
.hide_small_inline { /* 小画面 */
  display: none;
}
@media only screen and (min-width:651px) { /* 中画面&大画面 */
  .hide_small_inline {
    display: inline;
  }
}

中画面の時だけ、大画面の時だけ要素を非表示にするクラスは以下のようになります。

/* 中画面の時だけ要素を非表示にするクラス */
@media only screen and (min-width:651px) and (max-width:960px) { 
  .hide_medium {
    display: none;
  }
}

/* 大画面の時だけ要素を非表示にするクラス */
@media only screen and (min-width:961px) { 
  .hide_large {
    display: none;
  }
}

画面サイズに応じて要素を表示するクラス

前述のクラスとは逆に、大画面の時にだけ表示するというようなクラスも作成することができます。

以下は、大画面の時にだけ(ブロック)要素を表示するクラスの例です。

.show_large_block { /* 小画面&中画面 */
  display: none;
}
@media only screen and (min-width:961px) { /* 大画面 */
  .show_large_block {
    display: block;
  }
}

このクラスの場合、対象の要素がインライン要素やインライン・ブロック要素等の場合は、別途クラスを用意する必要があります。このため、「特定の画面幅の場合のみ表示する」と言うクラスは作成しないで、「特定の画面幅の場合のみ非表示にする」というクラスで代用する方法が良く用いられます。

例えば、大画面の場合のみ表示するようにするには、小画面と中画面の場合に非表示にするクラスを同時に指定します。(class="hide_small hide_medium")

以下は、Bootstrap3 で定義されている要素を表示・非表示するクラスの例です。

/* 非表示にするクラスの例 */
@media (max-width: 767px) {
  .hidden-xs {
    display: none !important;
  }
}
@media (min-width: 768px) and (max-width: 991px) {
  .hidden-sm {
    display: none !important;
  }
}
@media (min-width: 992px) and (max-width: 1199px) {
  .hidden-md {
    display: none !important;
  }
}
@media (min-width: 1200px) {
  .hidden-lg {
    display: none !important;
  }
}
/* 表示するクラスの例 */
.visible-xs,
.visible-sm,
.visible-md,
.visible-lg {
  display: none !important;
}
.visible-xs-block,
.visible-xs-inline,
.visible-xs-inline-block,
.visible-sm-block,
.visible-sm-inline,
.visible-sm-inline-block,
.visible-md-block,
.visible-md-inline,
.visible-md-inline-block,
.visible-lg-block,
.visible-lg-inline,
.visible-lg-inline-block {
  display: none !important;
}
@media (max-width: 767px) {
  .visible-xs {
    display: block !important;
  }
  table.visible-xs {
    display: table !important;
  }
  tr.visible-xs {
    display: table-row !important;
  }
  th.visible-xs,
  td.visible-xs {
    display: table-cell !important;
  }
}
@media (max-width: 767px) {
  .visible-xs-block {
    display: block !important;
  }
}
@media (max-width: 767px) {
  .visible-xs-inline {
    display: inline !important;
  }
}
@media (max-width: 767px) {
  .visible-xs-inline-block {
    display: inline-block !important;
  }
}
・・・省略・・・

垂直方向の余白の調整

レスポンシブデザインでは、大画面の場合は複数の列にコンテンツが横に並び、小画面の場合は1列で縦に並ぶようなケースが多く発生します。

その際に、垂直方向の余白(上下の間隔)の調整が必要になる場合があります。

以下のような HTML があり、md-6 クラスの div 要素は、画面幅が781px以上では 50% の幅で、780px以下では 100% で表示されます。

<section>
  <h2>Sample 1</h2>
  <div class="row foo">
    <div class="md-6"><img src="images/img-01.jpg" alt=""> </div>
    <div class="md-6">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
      <p>Deleniti eligendi dolor ea molestias, placeat magni vita...</p>
    </div>
  </div>
</section>  
.md-6 {
  position: relative;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}
@media (min-width: 781px) {
  .md-6 {
    float: left;
    width: 50%;
  }
}

p {
  margin-top: 0;
}

上記のページの幅を狭めた場合、以下の左側のような表示になります。右側は md-6 クラスの div 要素に padding-bottom:30px を指定した場合です。

サンプル

右側は画像の下の余白ができたのは良いのですが、今度は次のコンテンツとの間が広くなりすぎてしまいます。このため、何らかの方法で余白の調整をする必要があります。

余白を調整する方法は色々と考えられますが、以下は、2つ目(最後)の md-6 クラスの div 要素の padding-bottom を 0 に設定しています。そして、画面幅が 781px 以上の場合は、1つめの md-6 クラスの div 要素の padding-bottom も 0 にしています。また、この例の場合、md-6 クラスの親要素に foo と言うクラスを指定しています。

.md-6 {
  position: relative;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}

@media (min-width: 781px) {
  .md-6 {
    float: left;
    width: 50%;
  }
}

.foo .md-6 {
  padding-bottom: 30px;
}

.foo .md-6:last-child {
  padding-bottom: 0;
}

@media (min-width: 781px) {
  .foo .md-6 {
    padding-bottom: 0;
  }
}

※この例では、パディングで余白を指定していますが、この例の場合はマージンで余白を指定しても同じになります。padding-bottom: 30px、padding-bottom: 0 をそれぞれ margin-bottom: 30px、margin-bottom: 0 に書き換えるだけです。但し、マージンの相殺が発生するような構造の場合は、その限りではありません(マージンの相殺を利用した方が簡潔になる場合もあります)。次の例についても同様です。

サンプル(マージンで指定した場合:パディングで指定した場合と表示上は同じ)

余白を調整するクラス

場合によっては、垂直方向(上下)の間隔を調整するクラスを用意しておくと便利な場合があります。

以下は、sm_pad_btm という画面幅が 780px 以下の場合に padding-bottom:30px を設定するクラスを用意した場合の例です。sm_pad_btm というクラスを1つめの md-6 クラスの div 要素に指定しています。また、この例の場合、md-6 クラスの親要素に bar と言うクラスを指定しています。

<section>
  <h2>Sample 2</h2>
  <div class="row bar">
    <div class="md-6 sm_pad_btm"><img src="images/img1-02.jpg" alt=""> </div>
    <div class="md-6">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
      <p>Deleniti eligendi dolor ea molestias, placeat magni vita...</p>
    </div>
  </div>
</section>
.md-6 {
  position: relative;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}

@media (min-width: 781px) {
  .md-6 {
    float: left;
    width: 50%;
  }
}

@media only screen and (max-width:780px) {
  .bar .sm_pad_btm {
    padding-bottom: 30px;
  }
}

以下は前述の例とは逆に、sm_no_pad_btm という画面幅が 780px 以下の場合に padding-bottom:0 を設定するクラスを用意した場合の例です。全ての md-6 クラスの div 要素に padding-bottom:30px を設定しておき、画面幅が 780px 以下の場合、そのクラスは padding-bottom:0 になります。781px 以上の場合は、padding-bottom:0 を設定します。また、この例の場合、md-6 クラスの親要素に baz と言うクラスを指定しています。

<section>
  <h2>Sample 3</h2>
  <div class="row baz">
    <div class="md-6"><img src="images/img1-02.jpg" alt=""> </div>
    <div class="md-6 sm_no_pad_btm">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
      <p>Deleniti eligendi dolor ea molestias, placeat magni vita...</p>
    </div>
  </div>
</section>
.md-6 {
  position: relative;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}

@media (min-width: 781px) {
  .md-6 {
    float: left;
    width: 50%;
  }
}

.baz .md-6 {
  padding-bottom: 30px;
}
  
.baz .sm_no_pad_btm {
  padding-bottom: 0;
}

@media (min-width: 781px) {
  .baz .md-6 {
    padding-bottom: 0;
  }
}

レスポンシブイメージ

画面サイズやデバイスに応じて画像ファイルを切り替える(最適化する)手法を一般的にレスポンシブイメージと呼びます。また、HTML5(5.1)から導入された img 要素の srcset 属性、sizes 属性を使う方法やアートディレクションを実現する picture 要素を使う方法をレスポンシブイメージと呼びます。

画像 | Web | Google Developers

フルードイメージ

フルードイメージ(Fluid Image)とは、ブラウザのウィンドウ幅(親要素の幅)に合わせて画像のサイズをフィットさせる方法です。

ウィンドウサイズより大きい画像でも、ウィンドウサイズ(または親要素の幅)に応じて、縦横比を保持したまま自動的に画像が拡大・縮小するようにするには、img 要素に以下を指定します。

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

/*画像だけではなく動画などのメディアも含める場合の例*/
img, video, object {
  display: block;
  max-width: 100%;
  height: auto;
  width: 100%\9; /* IE8のみ適用(もう不要?) */
}

max-width: 100% ではなく width: 100% と指定すると、画像の幅が親要素の幅より小さかった場合、画像が拡大表示されてしまい画質が劣化したように見えてしまいます。

背景画像を比率を保ったまま伸縮

背景画像を比率を保ったまま伸縮させて表示するには height を 0 にして、padding-top を使って高さを確保し、% を使うことで比率を保ちます。

%を使う場合、親要素の横幅(width)が基準になるので、高さは (画像の高さ ÷ 画像の横幅) × 100 で算出できます。

<div class="bg_fluid">
  <p>1800 x 1195 の画像 <br>(1195/1800)*100=66.38888%;</p>
</div>    

背景画像は div 要素のパディング部分に表示されているので、子要素の p 要素は絶対配置にしています。

.bg_fluid {
  background-image: url(../images/sample_01.jpg);  
  width: 100%;
  height: 0;
  padding-top: 66.38888%;
  background-size: cover; /* この場合 contain でも同じ */
  background-repeat: no-repeat;
  background-position: center;  
  position: relative; /* 絶対配置する p 要素の基準とするため */
}      
.bg_fluid p {
  position: absolute;
  top: 50%;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%) ;
  color: #fff;
} 

1800 x 1195 の画像
(1195/1800)*100=66.38888%;

前述の例は画像の縦横比で表示しましたが、以下は画像の縦横比とは異なる 2:1 で表示する例です。

<div class="bg_fluid2"></div> 

この場合、background-size には cover を指定します。contain を指定すると全体を縦横比を保って表示するので切り取られた表示になります。

また、background-position で表示する部分を調整することができます。

.bg_fluid2 {
  background-image: url(../images/sample_01.jpg);  
  width: 100%;
  height: 0;
  padding-top: 50%;
  background-size: cover; /* この場合 contain にすると切り取られる */
  background-repeat: no-repeat;
  background-position: top;  
}  

背景画像の切り替え

画面サイズにより背景画像を変更するには、画面サイズに応じた画像を用意してメディアクエリを使って切り替えます(ヘッダ画像の項と同じ内容です)。

この例では、以下の3つの画像ファイルを用意して、メディアクエリを使って画像の高さと画像ファイルを変更しています。

  • header-img1_S.jpg(小画面用)800 x 207 (36KB)
  • header-img1_M.jpg(中画面用)1200 X 310 (73KB)
  • header-img1_L.jpg(大画面用)1800 x 465 (164KB)

以下が HTML です。header 要素内に div 要素を配置し、背景画像を設定する例です。

<header>
      ....
  <div id="header-img"></div> <!-- 背景画像でヘッダー画像を表示-->
      ...
</header>

1~6行目は小画面のスタイルです。div 要素の高さを指定し、背景画像を指定しています。

また、background-size: cover 及び background-position: bottom を指定しています。(これらは中画面及び大画面で共通の設定になります)

background-size に cover を指定して、全体を覆うように配置しています。cover を指定すると、背景画像の表示サイズが背景の表示領域全体をカバーするサイズに自動調整されます。 (背景画像の縦横比は維持されるので、「背景画像の縦横比」と「描画領域の縦横比」が一致しない場合は、背景画像の一部が切り取られます。)

また、この例では、background-position に bottom(center bottom)を指定しています。キーワードの指定が1つの場合、省略した値は center になります。

8~13行目は中画面での指定、15~20行目は大画面での指定です。メディアクエリを使って、div 要素の高さと画像ファイルを指定しています。

実際の画像の高さと、div 要素の高さが異なっていますが、background-size: cover を指定しているので、画像の縦横比は保持され、背景の表示領域全体をカバーするサイズに自動調整されます。

#header-img {  /* 小画面 */
  height: 200px;
  background-image: url("images/header-img1_S.jpg");
  background-size: cover;
  background-position: bottom;
}

@media only screen and (min-width:651px) {  /* 中画面 */
  #header-img {
    height: 250px;
    background-image: url("images/header-img1_M.jpg");
  }
}

@media only screen and (min-width:961px) {  /* 大画面 */
  #header-img {
    height: 300px;
    background-image: url("images/header-img1_L.jpg");
  }
}

レスポンシブデザインのサンプル2

img 要素の srcset 属性と sizes 属性

HTML 5.1 から導入された img 要素の srcset 属性と sizes 属性を使って画像を最適化することができます。

img 要素に srcset 属性と sizes 属性を設定し、サイズの異なる複数の画像を用意しておくことで、閲覧環境(幅やデバイスピクセル比)に適した画像が自動的に選択され表示されます。但し、IEではサポートされていません(http://caniuse.com/#search=srcset)。

同じ内容の画像で、サイズの異なる画像を切り替える場合に使用します。条件の設定は可能ですが、実際にどの画像が使用されるかはブラウザ側に委ねられます。

サイズの違いだけでなく、内容の異なる画像を設定する場合は「picture 要素と source 要素」を利用します。

srcset 属性には2つの指定方法があります。

1.ビューポート(ブラウザの表示領域/ウィンドウサイズ)の幅に応じて画像を切り替える指定

<img src="images/large.jpg" 
     srcset="images/small.jpg 320w, 
             images/medium.jpg 640w, 
             images/large.jpg 1280w" 
     sizes="(max-width: 1280px) 100vw, 1280px" 
     alt="srcset ビューポート サンプル画像">  

2.デバイスピクセル比に応じて画像を切り替える指定(Retinaディスプレイ用など)

<img src="images/sample.jpg"
     srcset="images/sample.jpg 1x,
             images/sample_2x.jpg 2x"
     alt="srcset デバイスピクセル比 サンプル画像">
属性の指定で使用する単位
単位 説明
w 幅記述子。ブラウザの幅により適切な幅の画像が選択されるように、画像の実際の幅のピクセル数を指定する際に使用します。
x 画素密度(解像度)記述子。1x で解像度1倍、2x で解像度2倍等を表し、デバイスピクセル比に応じて画像を切り替える際に使用します。
vw viewport widthの略。ビューポートの幅に対する割合(%)を指します。

以下はそれぞれの属性の概要です。

src 属性

画像の URL を指定する従来からの属性(必須)。srcset 属性と sizes 属性の属性に対応していないブラウザでは、src 属性で指定した画像が表示されます。

srcset 属性

使用される画像の選択候補をカンマ区切りで指定します。それぞれの画像候補には、画像ファイルの URL(画像へのパス)と画像の横幅(w)、またはデバイスピクセル比(x)のどちらかを半角スペースで指定することができます。(w)と(x)を混ぜて使用することはできません。

sizes 属性

画像の表示サイズ(横幅)を px 等の単位で指定します。割合で指定する場合は % ではなく vw 単位を使います。割合は親要素の幅に対するものではなく、ビューポートの幅に対するものになります。

単位 vw は Viewport Width (描画領域の横幅)の略です。100vw は、Viewport Width (描画領域の横幅)に対して100(%)という意味になります。

メディアクエリを指定することで、ブレイクポイントを設定することができます。

最後のアイテムではメディアクエリを省略し、この値が「デフォルトの横幅」となり、マッチするメディア・クエリがなかったときに使用されます。

sizes="(メディア・クエリ) 横幅, (メディア・クエリ) 横幅 ..., 横幅"

sizes="(max-width: 1280px) 100vw, 1280px"

上記は 1280px 以下の時 (max-width: 1280px) は画像をその画面幅(100vw)で表示し、それ以外では 1280px で表示する場合の記述になります。

このレスポンシブイメージでは、「画像ファイルの URL・ブラウザ 画像の横幅(srcset)、ブラウザの幅に応じて表示する画像幅(sizes)」の情報を元に、ブラウザが自動的にクライアントの環境に応じて最適な画像を表示します。

但し、環境に応じた最適な画像を決定する仕組みはブラウザによって異なり、ブラウザにより以下のような違いがあります。(2017年12月)

  • Chrome : 大きなサイズの画像ファイルをキャッシュした場合、画面幅を変更しても小さい画像は読み込まれません
  • Firefox : 画面幅を変更する都度、画面幅に応じたサイズの画像を読み込みます
  • Safari : 最初に開いた画面幅に応じた画像ファイルがキャッシュされ、画面幅を変更しても画像は再読み込みさません

srcset 属性と sizes 属性を設定した場合のブラウザの動作

  1. ブラウザはデバイスの幅を確認します
  2. sizes 属性のリストを調べてメディアクエリの条件を確認します。
  3. sizes 属性に指定されている表示サイズ(幅)を確認します。
  4. srcset 属性のリストにある画像で、表示サイズ(幅)に最も近い画像を読み込みます。

参考サイト:MDN レスポンシブ画像

以下は、3枚の画像(large.jpg、medium.jpg、small.jpg)を用意し、ブラウザの幅により表示する画像を切り替える例です。

<img src="images/medium.jpg" 
 srcset="images/small.jpg 640w, 
         images/medium.jpg 980w, 
         images/large.jpg 1280w" 
 sizes="100vw"
 alt="">

以下のスタイルが指定されています。

.container {
  max-width: 1400px;
  margin: 20px auto;
}
img {
  display: block;
  max-width: 100%;
  height: auto;
}

srcset 属性と sizes 属性のサンプル(Firefoxで確認するとわかりやすいです)

この例の場合、デバイスピクセル比(画素密度)が1でウィンドウサイズが
640px 以下なら small.jpg が、
980px 以下なら medium.jpg が、
981px 以上なら large.jpg が読み込まれます。

Retina ディスプレイなどデバイスピクセル比が2の場合は、ウィンドウサイズが 640px 以上の場合はウィンドウサイズは2倍の 1280px 以上となり large.jpg が読み込まれます。

また、srcset 属性と sizes 属性の属性に対応していないブラウザ(IE)では、src 属性で指定した画像(medium.jpg)が表示されます。

以下の場合、ウィンドウサイズが1280px 以下の場合は、ウィンドウ幅(100vw)に合わせて画像が表示され、1280pxを超えると1280pxの幅で表示されます。

<img src="images/medium.jpg" 
 srcset="images/small.jpg 640w, 
         images/medium.jpg 980w, 
         images/large.jpg 1280w" 
 sizes="(max-width: 1280px) 100vw, 1280px"
 alt="">

以下の場合、ウィンドウサイズが980px 以上の場合は、calc()関数を使って画面幅から300px引いた幅で表示され、980px未満の場合、幅いっぱいに表示されます。

<img src="images/medium.jpg" 
 srcset="images/small.jpg 640w, 
         images/medium.jpg 980w, 
         images/large.jpg 1280w" 
 sizes="(min-width: 980px) calc(100vw - 300px), 100vw"
 alt="">

picture 要素と source 要素

img 要素の srcset 属性と sizes 属性」での最適化とは異なり、サイズの違いだけでなく、内容の異なる画像を設定(アートディレクション)したい場合は picture 要素 source 要素を使用します。

picture 要素による設定では、指定した条件下で強制的に画像を切り替えることができます。(HTML 5.1 で追加されました。)

但し、IE ではサポートされていません。
ブラウザ実装状況:http://caniuse.com/#feat=picture

以下は、3枚の画像(large.jpg、medium.jpg、small.jpg)を用意し、ブラウザの幅により表示する画像を切り替える例です。

以下の場合、ウィンドウサイズが 961px 以上なら large.jpg が、651px 以上なら medium.jpg が 、650px 以下なら small.jpg が読み込まれます。

picture 要素をサポートしていないブラウザでは、img 要素に指定された large.jpg が表示されます。この例の場合、ヘッダ画像なので large.jpg を指定しています。実際にはヘッダ画像は「背景画像の切り替え」を利用したほうが良いでしょう。

<picture>
  <source media="(min-width: 961px)" srcset="images/large.jpg">
  <source media="(min-width: 651px)" srcset="images/medium.jpg">
  <source media="(min-width: 300px)" srcset="images/small.jpg">
  <img src="images/large.jpg" alt=""> 
</picture>   

ヘッダー画像に picture 要素と source 要素を使ったサンプル

ヘッダー画像の img 要素の幅に 100% を指定するだけのサンプル

基本的な記述方法

picture 要素は、単に画像候補のコンテナとして機能するだけで、詳細な設定はこの要素内に配置するsource要素(media 属性と srcset 属性)と img 要素で行います。

  • source 要素の media 属性を使ってメディアクエリを設定(条件を設定)
  • source 要素の srcset 属性を使って画像候補を指定(表示される画像を設定)
  • source 要素の sizes 属性を使って画像サイズを指定(幅記述子 w を使って幅を指定する場合は、sizes属性の指定も必要)
  • 必要に応じて複数の source 要素を配置
  • source 要素の後に img 要素を配置して、デフォルトで表示される画像を指定

img 要素は必ず最後に記述します。img 要素の後に書かれた source 要素はすべて無視されるので注意が必要です。また、ブラウザが picture 要素をサポートしていない場合には、自動的に img 要素に指定された画像が表示されます。

以下も、3枚の画像(large.jpg、medium.jpg、small.jpg)を用意し、ブラウザの幅により表示する画像を切り替える例ですが、前述の例とは異なり、メディアクエリには max-width を使って指定しています。

画面幅が 650px までは small.jpg を幅100%で表示し、651~1280px までは medium.jpg か large.jpg のどちらかを幅100%で表示、それ以外の場合は img 要素に指定した large.jpg を表示します。

また、2つ目の source 要素内の srcset 属性に複数の画像(medium.jpg と large.jpg)を指定しています。srcset 属性に指定された画像候補(medium.jpg と large.jpg)の切り替えはブラウザ側に依存します。(source 要素単位での切り替えは強制的に行われます。)

<picture>
  <source media="(max-width: 650px)" 
          srcset="images/small.jpg 650w" 
          sizes="100vw">
  <source media="(max-width: 1280px)" 
          srcset="images/medium.jpg 960w,
                  images/large.jpg 1280w" 
          sizes="100vw">
  <img src="images/large.jpg" alt="サンプル画像"> 
</picture>

picture 要素を使ったサンプル(Firefoxで確認するとわかりやすいです)※picture 要素は内容の異なる画像を設定するために使用しますが、このサンプルでは同じ内容の画像を使用しています。

以下は前述の例を min-width を使って書き換えたものです。ほぼ同じ動作をしますが、img 要素には、small.jpg を指定しているので、サポートしていないブラウザでは small.jpg が表示されます。

<picture>
  <source media="(min-width: 961px)"
          srcset="images/large.jpg 1280w"         
          sizes="100vw">
  <source media="(min-width: 651px)" 
          srcset="images/medium.jpg 650w" 
          sizes="100vw">
  <img src="images/small.jpg" alt="サンプル画像"> 
</picture>

デフォルトの画像を large.jpg とする場合は以下のように記述できます。

<picture>
  <source media="(min-width: 961px)"
          srcset="images/large.jpg 1280w"         
          sizes="100vw">
  <source media="(min-width: 651px)" 
          srcset="images/medium.jpg 650w" 
          sizes="100vw">
  <source media="(min-width: 100px)" 
        srcset="images/small.jpg" >
  <img src="images/large.jpg" alt="サンプル画像"> 
</picture>

以下は画面幅(ビューポート)と画像解像度(ピクセル密度)により画像を切り替える例です。

srcset 属性には複数の画像リソースを指定でき、それぞれの画像はカンマ区切りで記述します。

「1x」や「1.5x」「2x」という値は画像解像度を示しています。「1.5x」は通常の1.5倍の画像解像度の場合はこの画像を使用するように、と指定をします。「1x」の記述は省略可能です。

画面幅が 768px 以上では、画像解像度により
large.jpg (1x の場合)、
large_1.5x.jpg (1.5x の場合)、
large_2x.jpg (2x の場合)を表示します。

画面幅が 320px 以上では、
medium.jpg (1x の場合)、
medium_1.5x.jpg (1.5x の場合)、
medium_2x.jpg (2x の場合)を表示します。

それ以外の場合は img 要素に指定した
small.jpg (1x の場合)、
small_1.5x.jpg (1.5x の場合)、
small_2x.jpg (2x の場合)を表示します。

srcset 属性に指定された画像解像度による画像候補の切り替えはブラウザ側に依存します。

<picture>
  <source media="(min-width: 768px)" 
          srcset="images/large.jpg 1x,
                  images/large_1.5x.jpg 1.5x,
                  images/large_2x.jpg 2x" />
  <source media="(min-width: 320px)" 
          srcset="images/medium.jpg 1x,
                  images/medium_1.5x.jpg 1.5x,
                  images/medium_2x.jpg 2x" />
  <img src="images/small.jpg" 
       srcset="images/small_1.5x.jpg 1.5x,
               images/small_2x.jpg 2x"
       alt="サンプル画像" />
</picture>

picture 要素を使ったサンプル2(iPhone などで確認すると 2x の画像が表示されます)※picture 要素は内容の異なる画像を設定するために使用しますが、このサンプルでは同じ内容の画像を使用しています。

以下は画面幅 600px 以下の時には縦長の画像(sample-portrait@○x.jpg)をデバイスの解像度に合わせて表示し、画面幅 600px より大きい時は source 要素の srcset に表示候補の画像(sample@○x.jpg)のリストを指定して画面幅に応じてブラウザに最適な画像を選択させて表示する例です。

画面幅 600px 以上の場合に指定した画像のリストからどの画像が表示されるかやウィンドウサイズは変更した場合の動作はブラウザにより異なります。

<div class="wrapper">
  <picture>
    <source media="(max-width: 600px)" 
          srcset="sample-portrait@1x.jpg 1x,
                  sample-portrait@2x.jpg 2x,
                  sample-portrait@3x.jpg 3x">
    <source srcset="sample@1x.jpg 1200w,
                  sample@2x.jpg 2400w,
                  sample@3x.jpg 3600w"
          sizes="100vw">
    <img id="sampleImage" src="sample@3x.jpg"
     alt="サンプル画像"> 
  </picture>
</div> 

<!--
sample-portrait@1x.jpg : 600x800 /28kb
sample-portrait@2x.jpg : 1200x1600 /79kb
sample-portrait@3x.jpg : 1800x2400 /143kb
sample@1x.jpg 1200 :  1200x800 /49kb
sample@2x.jpg 2400 :  2400x1600 /143kb
sample@3x.jpg 3600 :  3600x2400 /260kb
 -->                 
                  

picture 要素を使ったサンプル

ポリフィル の利用

ポリフィル (polyfill) とは、最近の新しい機能をサポートしていない古いブラウザで、同等の機能を提供する方法のことです。

現時点(2017年)では、srcset 属性や picture 要素に対応していないブラウザもあるので、ポリフィルを利用するのも1つの方法です。

レスポンシブイメージの代表的なポリフィルとしては、「Picturefill / GitHub」があります。

但し、未対応ブラウザや特定のブラウザでは、マークアップの変更やフォールバックの対策などが必要になることがあるようです。以下のサイトに注意点等が書かれています。

レスポンシブイメージのポリフィル「Picturefill.js」でブレイクポイントによって画像を切り替える(tam-tam.co.jp)

respimage」と言うポリフィルもあります。こちらは、「html5shiv」や画像などを遅延読み込みするプラグイン「lazysizes」の作者によるものです。

文字のレスポンシブ対応

レスポンシブ・タイプセッティング

画面幅(ウインドウサイズ)によって文字サイズを変化させる手法をレスポンシブ・タイプセッティングと言います。レスポンシブ Web デザインでは、以下の理由で小画面のレイアウトの文字を小さめに指定することが多いです。

  • スマートフォンで閲覧する際は、PC やタブレットに比べて画面と顔の距離が近くなるので、小さい文字でも視認できる。
  • 幅の狭い画面で大きな文字を表示すると、一行あたりの文字が減り読みにくくなる。
  • 見出しなどが改行されて2行になってしまう。

以下は目安となる font-size の例です(あくまでも目安です)。

デバイス font-size
スマートフォン 12px 以上(12px~14px)
タブレット端末(768px以上) 14px 以上
デスクトップ(1024px以上) 16px 以上

画面幅に応じて文字のサイズを変更するには、メディアクエリを使って指定することができます。

以下はタイトルや本文にクラス名を指定した HTML の例です。

<section>
  <h1 class="title">Media Queries</h1>
  <p class="main-text">Animi sint corrupti ipsum sunt...</p>
  <section>
    <h2 class="title">Break Point</h2>
    <p class="main-text">Vitae, nam, aperiam pariatur dicta officia...</p>
    <p class="main-text">Possimus, error, a id totam cumque fugiat ...</p>
  </section>
  <section>
    <h2 class="title">Grid System</h2>
    <p class="main-text">Sapiente dolorum impedit commodi quaera...</p>
  </section>
</section>

以下は、上記 HTML のページを画面幅に応じて、文字サイズを変更する例です。

main-text クラスを指定した本文の p 要素は、画面幅が 650px 以下の場合は 14px、画面幅が651px~960px の場合は 16px、画面幅が961px 以上の場合は 17px で表示するようにメディアクエリを使って指定しています。同時に h1 や h2 のタイトルも画面幅に応じてサイズを変更しています。(これらのサイズは一例ですので、実際のサイズはデザインや環境に合わせて設定します)

レスポンシブ・タイプセッティングの例

h1.title, h2.title { /* 小画面用 */
  color: #333;
  line-height: 1.2;
  border-bottom: solid 1px #999;
  margin-bottom: 8px;
}
h1.title {
  font-size: 20px;
}
h2.title {
  font-size: 18px;
}
.main-text {
  font-size: 14px;
  line-height: 1.5;
}

@media only screen and (min-width:651px) { /* 中画面用 */
  h1.title {
    font-size: 24px;
  }
  h2.title {
    font-size: 20px;
  }
  .main-text {
    font-size: 16px;
  }
}

@media only screen and (min-width:961px) { /* 大画面用 */
  h1.title {
    font-size: 26px;
  }
  h2.title {
    font-size: 22px;
  }
  .main-text {
    font-size: 17px;
  }
}

相対単位 rem, em

前述の例では、文字のサイズを変更する要素やクラスに対して、メディアクエリを使ってサイズの変更をしましたが、相対単位 rem em を使うと基準となる値を変更することで個々の要素やクラスを指定せずに文字サイズを変更することができます。

rem (root em) はルート要素(html 要素)に対する相対的なフォントサイズの単位です。常に html 要素の値を基準とします。それに対して em は基準となる要素が親要素になるのと、マージンなどの設定ではその要素の font-size が基準になったり、入れ子にした場合、複利計算が発生するなど計算が多少複雑になります。※但し、rem は古いブラウザ(IE6~IE8等)ではサポートされていません。(caniuse: rem)

rem を使ったレスポンシブ・タイプセッティング

rem を使用する場合、html の font-size を 62.5% に指定する手法が良く用いられます。ほとんどのブラウザの初期値のフォントサイズは 16px に設定されています。このため、html 要素のフォントサイズを変更しない限り「1rem = 16px」となります(html 要素のフォントサイズを 100% とみなした場合)。

1rem を 10px にするには、10px ÷ 16px x 100% = 62.5% から html の font-size を 62.5% に指定します。これにより「1rem = 10px」となり、16px は、1.6rem となるので、計算が簡単になります。

また、この方法を使う場合、全ての文字のサイズ(font-size)を rem で指定する必要があります。加えて垂直方向のマージンやパディングも rem で指定することにより、それらの値も連動して変化させることができます。

以下は前述の例を rem を使って書き換えたものです。一部の要素しか掲載していませんが、全ての文字のサイズや垂直方向のマージンやパディングも rem で指定しています。

同じプロパティに対して px と rem で値を記述しているのは、rem をサポートしていないブラウザへのフォールバックです。(サポートしていないブラウザは px の値が適用されます)

rem を使ったレスポンシブ・タイプセッティングの例

html { /* 小画面用 */
  font-size: 62.5%;
}
body {
  font-size: 14px;
  font-size: 1.4rem;  /* 14px は 1.4rem */
  /* body 要素のフォントサイズを指定(10px にならないように) */
}

h1.title, h2.title {
  color: #333;
  line-height: 1.2;
  border-bottom: solid 1px #999;
  margin-bottom: 8px;
  margin-bottom: 0.8rem;
}
h1.title {
  font-size: 20px;
  font-size: 2.0rem;
}
h2.title {
  font-size: 18px;
  font-size: 1.8rem;
}

.main-text {
  font-size: 14px;
  font-size: 1.4rem;
  line-height: 1.5;
}

@media only screen and (min-width:651px) {
  html {
    font-size: 71.4286%;
  }
}

@media only screen and (min-width:961px) {
  html {
    font-size: 75.8929%;
  }
}

小画面(650px以下)では、本文のフォントサイズを 14px(この時の html の font-size は 62.5%)、中画面(651px~960px)では 16px、大画面(961px以上)では 17px で表示するように、メディアクエリで html 要素の font-size を指定しています。

例えば、中画面の場合は、16px で表示するので、html 要素の font-size は、16px ÷ 14px x 62.5% から 71.42857% としています。大画面の場合は同様に、17px ÷ 14px x 62.5% = 75.8929% としています。

但し、見出しなどは長さやデザインによって個別に大きさを調整する必要が出てくると思います。その場合、それらの指定は上記のメディアクエリの後に記述します。また、small 要素などを使用している部分も個別に調整する必要があるかも知れません。

ビューポートの単位(vw, vh, vmin, vmax)

vw, vh, vmin, vmax という相対単位(ビューポート・パーセンテージ)を利用することで、動的に文字サイズを変更することもできます。但し、現時点(2018年1月)では、サポートしていないブラウザもあり、特に文字サイズに関してはプロダクションでの利用はもう少し先になるかもしれません。

改行の調整

小画面では1行で表示できない可能性がある場合、意図しない位置での折り返しを避けるため、br 要素で改行位置を指定して改行させ、中画面、大画面では br 要素を非表示にして改行しないようにすることができます。

<h1 class="title">今一番お勧めの<br>コンパクトカーラインナップ</h1>
<p id="copyright"><small>Copyright (C) 2017 WDL </small><br>All rights reserved.</p>
@media only screen and (min-width:651px) {  /* 中画面&大画面 */
  h1.title br, #copyright br {
    display: none;
  }
}

または、以下のような中画面及び大画面では要素を非表示にするクラスを用意して br 要素に指定することもできます。(要素の表示・非表示

@media only screen and (min-width:651px) {  /* 中画面&大画面 */
  .hide_ML {
    display: none;
  }
}
<h1 class="title">今一番お勧めの<br class="hide_ML">コンパクトカーラインナップ</h1>
<p id="copyright"><small>Copyright (C) 2017 WDL </small><br class="hide_ML">All rights reserved.</p>

文字サイズ自動調整機能

text-size-adjust
text-size-adjust プロパティは一部のモバイル端末で使われる、テキストの自動拡大アルゴリズムを制御します。このプロパティは標準化されていないため、-moz-text-size-adjust, -webkit-text-size-adjust, -ms-text-size-adjust のように必ずプレフィックス付きで使用する必要があります。
can i use : text-size-adjust

iPhone や Android のブラウザには、テキストを読みやすいように大きさを自動で調整する機能が装備されています。但し、この機能の副作用として文字が勝手に拡大されてしまい、場合によってはレイアウトが崩れてしまうことがあります。

この現象を回避するには、-webkit-text-size-adjust というプロパティを使って自動調整機能を無効にします。デフォルトの値は auto(自動調整を行う)に設定されて、以下が指定できる値です。

  • none:ブラウザのテキスト自動拡大アルゴリズムを無効化します。(※ この値を指定するとくつかの PC 用のブラウザでページの拡大・縮小機能に支障がでるため指定しない方が良いようです)
  • auto:ブラウザのテキスト自動拡大アルゴリズムを有効化します。(デフォルト)
  • %(パーセント指定):ブラウザのテキスト自動拡大アルゴリズムを有効化し、パーセント値で文字サイズの倍率を指定します。

対策:html 要素(または body 要素)に -webkit-text-size-adjust : 100%; を指定します。

-webkit-text-size-adjust : 100%; を指定すると、iPhone の Safari で文字サイズが自動調整されるのを防ぐことができます。これを指定しないと、端末を回転させた時などに文字サイズが自動的に拡大される場合があります。

html {
  -webkit-text-size-adjust: 100%;  /* iOS用 */
  -ms-text-size-adjust: 100%;  /* IE Windows Phone用 */ 
}

以下は、Bootstrap の CSS の指定例です。

/* Bootstrap v3.3.7 */
html {
  font-family: sans-serif;
  -webkit-text-size-adjust: 100%;
      -ms-text-size-adjust: 100%;
}

/* Bootstrap v4.0.0-beta.2  */
html {
  font-family: sans-serif;
  line-height: 1.15;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  -ms-overflow-style: scrollbar;
  -webkit-tap-highlight-color: transparent;
}

-ms-overflow-style: scrollbar

IE10、IE11、Edge でスクロールバーがコンテンツと重なる現象が発生する場合があります。これは IE、Edge で、viewport の width の値が device-width の場合に発生するようです。

回避策としては、-ms-overflow-style プロパティを scrollbar として指定すれば良いようです。

html {
  -ms-overflow-style: scrollbar;
}

-webkit-tap-highlight-color

iPhone や iPad 等で、リンクをタップした際にハイライト表示されますが、-webkit-tap-highlight-color プロパティを使って無効にしたり、ハイライトカラーを変更することができます。

色を変更する場合は、このプロパティの値に色を指定します。

a {
 -webkit-tap-highlight-color: rgba(187,244,243,1.00); /* RGBA で指定可能*/
}

値に transparent を指定することで無効にすることができます。

html {
  -webkit-tap-highlight-color: transparent;
}

参考:サイト上でのタップ操作をサポートする

アンチエイリアスの調整

Webkit 系のブラウザでは、大きな文字をきれいに表示するためにアンチエイリアスが強くかかり、文字が太って表示されてしまいもっさりした感じに見えることがあります。

Windows には対応していませんが、Mac 版の Webkit 系と FireFox では、「-webkit-font-smoothing」と「-moz-osx-font-smoothing」でアンチエイリアスのかけ方を調整できます。

フォントにアンチエイリアス処理をして滑らかに表示する指定例です。

.foo {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

Webkit 系ブラウザ(Safari/Google Chrome/Android等)では以下の値が指定可能です。

Webkit 系
-webkit-font-smoothing: none; ぎざぎざ(アンチエイリアスなし)
-webkit-font-smoothing: subpixel-antialiased; デフォルト
-webkit-font-smoothing: antialiased; 滑らか

FireFox(Mac版)では以下の値が指定可能です。

FireFox
-moz-osx-font-smoothing: auto; ブラウザが自動で最適な値を設定
-moz-osx-font-smoothing: inherit; 親要素から継承
-moz-osx-font-smoothing: grayscale; 滑らか
-moz-osx-font-smoothing: unset; アンチエイリアスなし

但し、フォントサイズが小さい場合や、背景色とのコントラストによっては可読性を損なう可能性もあるので注意が必要です。

ビューポート・パーセンテージ

ビューポートの単位(ビューポート・パーセンテージ)はビューポートのサイズを基準にした相対単位で、ビューポートのサイズ(幅や高さ)により変化します。以下の4種類があります。

ビューポート単位(Viewport Units)
単位(Unit) 意味 説明
vw Viewport Width ビューポートの幅に対する割合
1vw = ビューポートの幅の 1/100
vh Viewport Height ビューポートの高さに対する割合
1vh = ビューポートの高さの 1/100
vmin Viewport Minimum ビューポートの幅か高さの小さい方に対する割合
1vmin = ビューポートの幅か高さの小さいほうの 1/100
vmax Viewport Maximum ビューポートの幅か高さの長い方に対する割合
1vmax = ビューポートの幅か高さの大きいほうの 1/100

ブラウザ対応状況:caniuse:viewport-units

ビューポートとは簡単に言うと表示領域(仮想ウィンドウサイズ)のことです。つまりこの単位を使うとデバイスの表示領域に対する割合を指定することができます。また、ブラウザのサイズが変更されるたびに値が変化する動的な値になります。

パーセント(%)指定の場合は親要素に対する割合(子要素の幅や高さは親要素の幅や高さに対する割合)になりますが、ビューポートの単位の場合は常にデバイスの表示領域に対する割合になります。

表示領域(ビューポート)の横幅全体が「100vw」になるので、10vw と指定すると、表示領域の幅に対して 1/10 (10%) のサイズを指定することになります。

vw(Viewport Width)

vw(Viewport Width)はビューポートの幅を基準にそのサイズを決定します。また、ビューポートの幅は、ブラウザのスクロールバーを含んだサイズで算出されます。

以下は、各 div 要素の幅を vw と % で指定した場合の例です。vw で幅を指定したレイアウトは、画面の高さを小さくして、スクロールバーが表示されるとレイアウトは崩れてしまいます。

幅を vw と % で指定した場合の例

<body>
  <h1>vw</h1>
  <p>画面の高さを小さくして、スクロールバーが表示されると、vw で指定したレイアウトは崩れます。</p>
<div class="hundred blue">width: 100vw</div>
<div class="row">
  <div class="fifty green fleft">width: 50vw</div>
  <div class="fifty yellow fleft">width: 50vw</div>
</div>
<div class="row">
  <div class="twentyfive pink fleft">width: 25vw</div>
  <div class="twentyfive yellow fleft">width: 25vw</div>
  <div class="twentyfive blue fleft">width: 25vw</div>
  <div class="twentyfive green fleft">width: 25vw</div> 
</div>
  <h2>%</h2>
  <div class="hundred-p blue">width: 100%</div>
<div class="row">
  <div class="fifty-p green fleft">width: 50%</div>
  <div class="fifty-p yellow fleft">width: 50%</div>
</div>
<div class="row">
  <div class="twentyfive-p pink fleft">width: 25%</div>
  <div class="twentyfive-p yellow fleft">width: 25%</div>
  <div class="twentyfive-p blue fleft">width: 25%</div>
  <div class="twentyfive-p green fleft">width: 25%</div> 
</div>
</body>
* {
  margin: 0;
  padding: 0;
}
div {
  text-align: center;
  line-height: 60px;
}
.hundred, .fifty, .twentyfive {
  height: 60px;
}
.hundred {
  width: 100vw;
}
.fifty {
  width: 50vw;
}
.twentyfive {
  width: 25vw;
}
.hundred-p, .fifty-p, .twentyfive-p {
  height: 60px;
}
.hundred-p {
  width: 100%;
}
.fifty-p {
  width: 50%;
}
.twentyfive-p {
  width: 25%
}
.blue {
  background: #B3D1F4;
}
.green {
  background: #B9F6B2;
}
.yellow {
  background: #F5F691;
}
.pink {
  background: #F7CECF;
}
.fleft {
  float: left;
}
.row:after { /* clearfix */
  display: table;
  content: "";
  clear: both;
}

vh (Viewport Height)

vh (Viewport Height)はビューポートの高さを基準にそのサイズを決定します。以下は、各 div 要素の高さを 25vh に指定した例です。4つの div 要素の高さの合計は 100vh(画面の高さ)になり、画面の高さを変更してもスクロールバーは表示されません。

高さを vh で指定した場合の例

<body>
<div class="blue">width: 100vw / height: 25vh</div>
<div class="green">width: 100vw / height: 25vh</div>
<div class="yellow">width: 100vw / height: 25vh</div>
<div class="pink">width: 100vw / height: 25vh</div>
</body>
* {
  margin: 0;
  padding: 0;
}

div {
  width: 100vw;
  height: 25vh;
  text-align: center; 
}

vh を利用すると、デバイスのサイズにかかわらず画面いっぱいに背景イメージを表示することが間単にできます。また、同様にページの各セクションを画面いっぱいに表示させることもできます。

.fullscreen {
  background: url(../images/sample_01.jpg) center/cover;
  width: 100%;
  height: 100vh;
}
section {
  width: 100%;
  height: 100vh;
}

サンプル

画面いっぱいに背景イメージを表示したり、各セクションを画面いっぱいに表示させる例はこちら(Viewport Height)を参照ください。

開閉式ナビゲーションメニュー

スマートフォンなどの小画面のデバイスでは、スペースを有効活用するために開閉式のナビゲーションメニューがよく利用されます。

以下は、開閉式のナビゲーションバーを追加する前の、基本的なナビゲーションのマークアップとスタイルです。(レイアウト・ナビゲーションメニュー 参照)

<nav> 
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">News</a></li>
    <li><a href="#">Photo</a></li>
    <li><a href="#">Sample</a></li>
    <li><a href="#">FAQ</a></li>
    <li><a href="#">About</a></li>
  </ul> 
</nav> 

4行目から~11行目は、650px 以下の場合の li 要素(メニュー項目)のスタイルの指定で、左寄せで幅50%で表示し、ボーダーを指定しています。

12行目から~21行目は、651px 以上の場合の li 要素(メニュー項目)のスタイルの指定で、各項目を16.66666667%(100/6)の幅に指定して横一列に表示します。

22行目から~31行目は、650px 以下の場合の a 要素(リンク)のスタイルの指定です。display: block で a 要素をブロックレベル要素に変更してリンクの範囲を拡張し、メニュー項目の高さを line-height: 48px に指定しタップしやすい高さを指定しています。

32行目から~38行目は、651px 以上の場合の a 要素(リンク)のスタイルの指定です。

nav ul {
  list-style-type: none;
}
nav li {
  width: 50%;
  float: left;
  border-bottom: solid 2px #355B8E;
}
nav li:nth-child(odd) {
  border-right: solid 2px #355B8E;
}
@media only screen and (min-width:651px) {
  nav li {
    width: 16.66666667%;
    border-right: solid 2px #355B8E;
    border-bottom: none;
  }
  nav li:last-child {
    border-right: none;
  }
}
nav a {
  display: block;
  background: #030D2E;
  color: #FFF;
  font-weight: bold;
  font-size: 13px;
  line-height: 48px;
  padding-left: 15px;
  text-decoration: none;
}
@media only screen and (min-width:651px) {
  nav a {
    line-height: 36px;
    text-align: center;
    padding-left: 0;
  }
}
nav a:hover {
  background: #3B6FB5;
  text-decoration: underline;
}
nav ul:after {
  display: table;
  content: "";
  clear: both;
}

650px 以下では以下のような表示になります。

上記のメニューに開閉式ナビゲーションを追加して以下のようなナビゲーションメニューを作成します。

小画面のレイアウトでは、(バーガーアイコン) が表示されている領域をタップすることでメニュー項目の表示・非表示を切り替えます。

以下が開閉式メニューのマークアップです。

nav 要素と ul li 要素で構成した基本的なメニュー構造に、メニューの表示・非表示を切り替えるバーの領域のマークアップ(2行目の div 要素)を追加しています。

650px 以下ではこの部分のみを表示し、651px 以上ではこの部分を非表示にして、メニュー項目を表示します。(サンプル

バーガーのアイコン アイコンフォント <i class="fa fa-bars"></i> を使用しています。

<nav>
  <div><a href="#" id="pull"><i class="fa fa-bars"></i> Menu</a></div>
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">News</a></li>
    <li><a href="#">Photo</a></li>
    <li><a href="#">Sample</a></li>
    <li><a href="#">FAQ</a></li>
    <li><a href="#">About</a></li>
  </ul> 
</nav>

1行目~9行目は追加した表示・非表示を切り替えるバーの領域(id="pull" の div 要素)のスタイルの指定です。(9行目の display: block は後の nav a のスタイルでも指定されているので実際には不要です)

10行目~15行目はアイコンフォントのスタイルの指定です。#pull と #pull i もタップしやすいように高さを 48px に指定しています。

16行目~19行目は 650px 以下ではメニューの各項目を非表示にしています。(表示・非表示の切り替えは jQuery を利用します)

20行目~27行目は 651px 以上では表示・非表示を切り替えるバーの領域を非表示にして、メニューの各項目を表示するようにしています。

36行目~38行目は nth-child() を使って最初の2つの li 要素のボーダートップのスタイルを指定しています。

39行目~51行目は 651px 以上での li 要素(メニュー項目)のスタイルの指定です。

#pull { /* 追加 */  
  background: #030D2E;
  color: #FFF;
  font-weight: bold;
  font-size: 16px;
  line-height: 48px;
  padding-left: 15px;
  display: block;
}
#pull i  {
  padding-right: 10px;
  font-size: 150%;
  line-height: 48px;
  vertical-align: middle;
}
nav ul {
  list-style-type: none;
  display: none; /* 追加 */  
}
@media only screen and (min-width:651px) { /* 追加 */  
  #pull {
    display: none;
  }
  nav ul {
    display: block;
  }
}
nav li {
  width: 50%;
  float: left;
  border-bottom: solid 2px #355B8E;
}
nav li:nth-child(odd) {
  border-right: solid 2px #355B8E;
}
nav li:nth-child(-n+2){
  border-top: solid 2px #355B8E; /* 追加 */  
}
@media only screen and (min-width:651px) {
  nav li {
    width: 16.66666667%;
    border-right: solid 2px #355B8E;
    border-bottom: none;
  }
  nav li:last-child {
    border-right: none;
  }
  nav li:nth-child(-n+2){
    border-top: none; /* 追加 */  
  }
}
nav a {
  display: block;
  background: #030D2E;
  color: #FFF;
  font-weight: bold;
  font-size: 13px;
  line-height: 48px;
  padding-left: 15px;
  text-decoration: none;
}
@media only screen and (min-width:651px) {
  nav a {
    line-height: 36px;
    text-align: center;
    padding-left: 0;
  }
}
nav a:hover {
  background: #3B6FB5;
  text-decoration: none; 
}
nav ul:after {
  display: table;
  content: "";
  clear: both;
}

jQuery を使った表示・非表示

メニュー項目の表示・非表示(開閉)の機能は JavaScript(jQuery)を利用します。

jQuery を使用するので、jQuery を body 要素の閉じタグの直前で読み込みます。以下は Google の CDN 経由で jQuery を読み込み、pull_menu.js という jQuery を記述するファイルを js フォルダ内に配置した場合の例です。(参考:jQuery の読み込み

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> 
<script src="js/pull_menu.js"></script> 
</body>

または、以下のように<script>~</script> に JavaScript(jQeury) を記述することもできます。(参考:jQuery の記述場所

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> 
<script>
    //ここに jQuery の処理を記述
</script>
</body>

以下は、メニューを開閉(表示・非表示)する jQuery です。任意の名前のファイル(上記の例の場合は、pull_menu.js という名前のファイル)か、<script>~</script> に記述します。この例では<script>~</script> に記述します。

1行目の jQuery(function($){ と14行目の }); は、jQuery を利用する際のおまじないのようなもので、この中に jQuery を記述します。(参考:jQuery の ready 関数「ドキュメント・レディ」ハンドラ

2行目の var menu = $('nav ul'); は変数 menu に $('nav ul') を代入しています。つまり、変数 menu は $('nav ul') を意味します。

3行目は、クリックイベントの処理の開始で、#pull の要素をクリックした際の処理を続く4~5行目に記述しています。

4行目の e.preventDefault(); は、リンクをクリックした際のデフォルトの動作(ページへの移動)を抑止する記述です。(参考:標準処理のキャンセル

5行目の menu.slideToggle(); が slideToggle() を使ったメニューバーの表示・非表示の記述です。menu は $('nav ul') なので、nav ul 要素をスライドのアニメーションで表示・非表示にしています。

jQuery(function($){
  var menu = $('nav ul');
  $('#pull').on('click', function(e) {
    e.preventDefault();
    menu.slideToggle();
  });
  
  var timer = false;
  $(window).resize(function() {
    if (timer !== false) {
      clearTimeout(timer);
    }
    timer = setTimeout(function() {
      var w = $(window).width();
      if(w > 650 && menu.css('display') == 'none') {
        menu.removeAttr('style'); //または menu.css("display", "block");
      }
    }, 200);
  });
});

8~19行目は、PC でブラウザの横幅を変更(リサイズ)した場合の処理の記述です。

651px 未満の状態でメニューバーをクリックしてメニュー項目を閉じると、slideToggle() により、nav ul 要素に対して display:none が設定されます。この状態でウィンドウ幅を広げてしまうとメニューが表示されないので、removeAttr('style') を使って jQuery によって変更されたスタイル(display:none)を初期化しています。

15行目のif(w > 650 && menu.css('display') == 'none') は、メニュー(nav ul 要素)の display の値が none で、かつその幅が650pxより大きい場合という条件です。

menu.css('display') == 'none' は is() を使って menu.is(':hidden') としても同じです。

リサイズイベントの場合、ウインドウをドラッグしている間連続して指定した処理が短い間隔で何回も呼ばれてしまうので、setTimeout() と clearTimeout() を利用して処理しています。

メニューのラベルを変更する場合

以下は、メニューバーをクリックした際にメニューのラベルを変更する例です。toggleLabel() というラベルを変更する関数を作成して、slideToggle() のコールバック関数で呼び出しています。

var pull = $('#pull');
var menu = $('nav ul');
var menuOpen = false; /* メニュー項目が表示されているかどうかの状態を示すフラグ */

function toggleLabel() {
  if(menuOpen){
    menuOpen = false;
    pull.html('<i class="fa fa-bars"></i> Menu');
  }else{
    menuOpen = true;
    pull.html('<i class="fa fa-window-close"></i> Close');
  }  
}

pull.on('click', function(e) {
  e.preventDefault();
  menu.slideToggle(240,function(){toggleLabel();});
});

var timer = false;
$(window).resize(function() {
  if (timer !== false) {
    clearTimeout(timer);
  }
  timer = setTimeout(function() {
    var w = $(window).width();
    if(w > 650 && menu.is(':hidden')) {
      menu.removeAttr('style');
    }
    adjust_menu();
  }, 200);
});

上記の方法の場合、slideToggle() のコールバック関数を使っているため、ラベルが変更されるタイミングがスライドのアニメーションが終了後に実施されるので、ほんの少しの時差があります。

メニューバーをクリックすると同時にラベルを変更するには、slideToggle() の代わりに、slideUp() と slideDown() を使って以下のように記述することができます。

var pull = $('#pull');  
var menu = $('nav ul');   
var menuOpen = false;

pull.on('click', function(e) {  
  e.preventDefault();    
  if(menuOpen){
    menu.slideUp();
    menuOpen = false;
    pull.html('<i class="fa fa-bars"></i> Menu');
  }else{
    menu.slideDown();
    menuOpen = true;
    pull.html('<i class="fa fa-window-close"></i> Close');
  }    
}); 

var timer = false;
$(window).resize(function() {
  if (timer !== false) {
    clearTimeout(timer);
  }
  timer = setTimeout(function() {
    var w = $(window).width();
    if(w > 650 && menu.is(':hidden')) {
      menu.removeAttr('style');
    }
    adjust_menu();
  }, 200);
});

サンプル

メニューを固定表示

以下のサンプルは画面幅が 650px 以下の場合、ナビゲーションメニューを画面上部に固定する例です。画面をスクロールしても常にナビゲーションメニューが固定で表示されているため、いつでも他のページへ移動することができます。

サンプル

JavaScript は前述と同じですが、HTML のマークアップは1箇所だけ、以下の nav 要素に ID(global_navi)を追加しています。

<nav id="global_navi">
  <div><a href="#" id="pull"><i class="fa fa-bars"></i> Menu</a></div>
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">News</a></li>
    <li><a href="#">Photo</a></li>
    <li><a href="#">Sample</a></li>
    <li><a href="#">FAQ</a></li>
    <li><a href="#">About</a></li>
  </ul> 
</nav>

以下が CSS の変更(追加)部分です。

#global_navi { /*  追加  */
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
}

body {/*  追加  */
  padding-top: 48px;
}

@media only screen and (min-width:651px) { 
  #global_navi { /*  追加  */
    position: relative;  //または static
  }
  body { /*  追加  */
    padding-top: 0;
  }
  #pull {
    display: none;
  }
  nav ul {
    display: block;
  }
}

1行目~6行目:ID(global_navi)を指定した nav 要素を固定配置(position: fixed)にして、位置(top と left)を指定しています。また、画面幅に合わせて表示するように width: 100% を指定しています。

8行目~10行目:position: fixed でメニューを上部に固定配置すると、メニューは通常フローから外れ他の要素に重なるように配置されるため、その高さの分を body 要素に余白(padding)として設定します。(高さの分 48px より少し大きめに指定しても良いかも知れません)

13行目~15行目:画面幅が651px 以上の場合は、固定配置ではなく元の配置に戻す必要があります。元の position の値に戻します。

16行目~18行目:画面幅が651px 以上の場合は、固定配置ではなく元の配置になるので、先に指定した 48px の余白を解除して、padding-top: 0 に戻します。

メニューを下部に固定配置

以下のサンプルはナビゲーションメニューを画面下部に固定する場合の例です。

サンプル

前述の例とほぼ同じで、違いは top の代わりに bottom で位置を指定しているのと(3行目)、body 要素への余白を padding-bottom(8行目と15行目)で指定しいる部分です。

また、フッターの色とメニューの色が同じなので、メニューの色を半透明にしています。

#global_navi {
  position: fixed;
  bottom: 0; /*  変更  */
  left: 0;
  width: 100%;
}

body {
  padding-bottom: 48px; /*  変更  */
}

@media only screen and (min-width:651px) { 
  #global_navi { 
    position: relative; //または static
  }
  body { 
    padding-bottom: 0; /*  変更  */
  }
  #pull {
    display: none;
  }
  nav ul {
    display: block;
  }
}

スクロールすると固定する例

ページをスクロールして、ちょうどメニューが画面上部の位置に来た時にメニューをその位置に固定する例です。

サンプル

メニューの固定は JavaScript/jQuery で設定します。

オリジナルのサンプル(メニューを固定しないサンプル)との CSS の違いは以下のみです。ID(global_navi)を指定した nav 要素に最大幅(max-width: 1130px)を指定しています。

このページの最大のサイズは 1160px ですが左右にパディングが 15px ずつあるので、1130px としています。

#global_navi {
  width: 100%;
  max-width: 1130px; /*  追加  */
}

以下が、メニューが画面上部の位置に来た時にメニューをその位置に固定するための jQuery の記述です。

15行目:変数 navi に nav 要素の jQuery オブジェクトを代入しています(後で何回か使用するため)。

16行目:offset() を使って画面トップからの nav 要素の位置を取得しています。offset() は要素の位置(ピクセル単位)を文書の原点からの相対位置で返します(単位は付いていません)。

18行目~30行目がメニューの位置を調整する関数の定義です。この関数をスクロールイベントとリサイズイベントで利用します。

20行目:scrollTop() を使って要素のスクロール位置を取得します。

22行目~14行目:画面幅が 1130px 以上の場合のメニューの中央寄せの指定です。固定配置(position:fixed)にすると、通常フローから外れるため、margin: auto が効かないので画面幅からページの最大幅(1130px)を引いて、それを2で割った値を変数 nav_margin_left に代入しておき、26行目で margin-left に指定しています。

25行目~26行目:画面トップからスクロールした距離がメニューの位置と同じかそれ以上になった場合に、メニューを css() で固定配置にし、top と left を 0 に、左マージンを指定して中央寄せに、そして色を半透明にしています。

27行目~28行目:スクロールした距離がメニューの位置に到達しない場合は、26行目で指定したスタイルを削除して通常のメニューの位置に戻します。

33行目~35行目:スクロールイベントを使って、スクロールした際に上記で定義した関数(adjust_menu())を実行します。

また、リサイズの処理の際にも、定義した関数(adjust_menu())を実行するように指定しています(リサイズの際の位置の調整がそれほど気にならなければ、不要かもしれません)。

var timer = false;
$(window).resize(function() {
  if (timer !== false) {
    clearTimeout(timer);
  }
  timer = setTimeout(function() {
    var w = $(window).width();
    if(w > 650 && menu.is(':hidden')) {
      menu.removeAttr('style');
    }
    adjust_menu(); /* メニュー位置の調整の関数 */ 
  }, 200);
});   

var navi = $('#global_navi');
var navTop = navi.offset().top; //navの原点からの相対位置

function adjust_menu() {
  var ww = $(window).width(); /* 画面幅の取得 */ 
  var winTop = $(this).scrollTop(); /* 画面トップからスクロールした距離 */
  var nav_margin_left = 0;
  if(ww > 1130) { 
    nav_margin_left = (ww -1130) / 2;//中央寄せ
  }
  if (winTop >= navTop) { //ナビゲーションの固定
    navi.css({position:'fixed', top: 0, left: 0, marginTop: 0, marginLeft: nav_margin_left, opacity: 0.85});
  } else (winTop <= navTop) {
    navi.removeAttr('style');
  }
}
   
//スクロールイベント
$(window).scroll(function () {
  adjust_menu();
});

jQuery のみで固定表示

前述の例では、CSS の position: fixed を使用してメニューバーを固定表示しましたが、以下は jQuery のみでメニューバーを固定する例です。

この例では、ユーザーが画面をスクロールしてメニューバーの位置に達するとメニューバーが画面上部に固定されたように表示されます。

サンプル

8行目:スクロールしてメニューバーの位置に来たら、メニューバーの位置を offset() を利用して画面トップからスクロールした距離にすることで、画面上部に固定しているように表示しています。また、その際にメニューバーを半透明にしています。

10行目:メニューバーの上に位置する領域の高さを outerHeight() を使って算出して、それを変数 hh に代入しています。

11行目:スクロールの距離がメニューバーの位置より小さくなった場合は、メニューバーを元の位置に戻し、半透明を解除しています。

var navi = $('#global_navi');
var navTop = navi.offset().top; //navの位置
   
//スクロールイベント
$(window).scroll(function () {
  var winTop = $(this).scrollTop(); /* 画面トップからスクロールした距離 */
  if (winTop >= navTop) { 
    navi.offset({top:winTop}).css("opacity", 0.86);
  } else {
    var hh = $("#header-img").outerHeight() + $("#header-top").outerHeight();
    navi.offset({top:hh}).removeAttr('style');
  }
});

テーブルのレスポンシブ対応

table 要素に width: 100% を指定し、セルの幅を特に指定しなければ画面幅に合わせてテーブルは伸縮しますが、内容によってはうまく収まらない場合があります。はみ出す部分がそれほど大きくない場合は、パディングや文字サイズの調整、または以下のような指定でうまく収まる可能性もあります。

table {
  width: 100%;
  table-layout: fixed;
  word-break: break-all;
}

table-layout: fixed は指定がない列の列幅は、テーブルの残りの幅に合わせて均等に分割されます。

word-break: break-all は、どの文字の間でも改行するようにする指定です。

但し、表の内容によってははみ出してしまったり、収まったとしても各列が非常に狭く縦長になり、読みにくい表示なってしまう場合があります。

そのような場合、以下のような方法を利用すると表を見易く表示できることがあります。

table にスクロールバーを表示

1つは、CSS を使ってテーブルを横方向にスクロールさせる方法です。

以下のようにスクロールバーを表示して、テーブルの内容をスクロールして見えるようにします。

table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data

以下はスクロールバーを表示する前のテーブルのマークアップと CSS です。

<table>
  <tr>
    <th>table head </th>
    <td>table data</td>
    <td>table data</td>
    <td>table data</td>
    <td>table data</td>
  </tr>
  ・・・中略・・・
  <tr>
    <th>table head</th>
    <td>table data</td>
    <td>table data</td>
    <td>table data</td>
    <td>table data</td>
  </tr>
</table>
table {
  border-collapse: collapse;
}
th {
  padding: 10px;
  text-align: left;
  color: #333;
  background-color: #ececec;
  border: 1px solid #b9b9b9;
}
td {
  padding: 10px;
  border: 1px solid #b9b9b9;
}

スクロールバーを表示するようにするには、table 要素を div 要素で囲みます。この例では div 要素に scroll_table と言うクラス名を指定しています。

<div class="scroll_table"> <!-- div 要素で table を囲む -->
  <table>
    <tr>
      <th>table head </th>
      <td>table data</td>
      <td>table data</td>
      <td>table data</td>
      <td>table data</td>
    </tr>
    ・・・中略・・・
    <tr>
      <th>table head </th>
      <td>table data</td>
      <td>table data</td>
      <td>table data</td>
      <td>table data</td>
    </tr>
  </table>
</div>

そして table 要素を囲んだ div 要素(.scroll_table)に以下のようなスタイルを指定します。

.scroll_table {
  width: 100%;
  overflow-x: auto;  /* 水平方向のスクロールバーを表示*/
  overflow-y: hidden;  /* 垂直方向のスクロールバーを非表示*/
}
.scroll_table th, .scroll_table td {
  white-space: nowrap;  /*テーブル内のテキストが折り返さないように指定*/ 
}

table 要素を囲んだ div 要素(.scroll_table)に width: 100% を指定することで、画面幅によって伸縮します。

overflow-x: auto を指定することで、div 要素がそのコンテンツである table 要素の幅より狭くなると、水平方向にスクロールバーを表示するようになります。

overflow-y: hidden は、overflow-x: auto を指定することにより、垂直方向のスクロールバーが表示される場合があるので、それを抑止します。

6行目~8行目は、セルの内容により異なってきますが、この例のように短い文字列の場合は、white-space: nowrap を指定することにより、テキストを折り返さないようにして見易くしています。テキストが折り返されると、セルの幅が狭くなり列が縦長になってしまいます。

セルの内容によっては、white-space: nowrap を指定する代わりに、th 要素や td 要素に幅(width)や最小幅(min-width)を指定します。以下は、th 要素に white-space: nowrap を指定し、td 要素に min-width: 140px を指定した例です。

.scroll_table th {
  white-space: nowrap;
}
.scroll_table td {
  min-width: 140px;
  /*white-space: normal;*/  
}

table head table data responseive table table data responseive table table data responseive table table data responseive table
table head table data responseive table table data responseive table table data responseive table table data responseive table
table head table data responseive table table data responseive table table data responseive table table data responseive table

スクロールバーのスタイルの指定

Webkit(Chrome、Safari)用になりますが、以下のようなスタイルを指定することができます(IE や Firefox ではブラウザのデフォルトのスクロールバーが表示されます)。

.scroll_table::-webkit-scrollbar {
  height: 15px; /*スクロールバーの高さ*/
}
.scroll_table::-webkit-scrollbar-track {  /*スクロールバーのトラック部分*/
  background:#AFD5F9;
  -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
}
.scroll_table::-webkit-scrollbar-thumb {  /*スクロールバーを動かす部分*/
  border-radius: 7.5px;
  background:#95A9BF;
  -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
}

トラック部分を更に分けて指定することもできます。

.scroll_table::-webkit-scrollbar-track-piece:start{ 
  background: #E2F8CD;
}
.scroll_table::-webkit-scrollbar-track-piece:end{ 
  background: #F9D6D6;
}

以下は画面幅が 640px 以下の場合、テーブルにスクロールバーを表示する場合の CSS の例です。

table {
  border-collapse: collapse;
}
th {
  padding: 10px;
  text-align: left;
  color: #333;
  background-color: #ececec;
  border: 1px solid #b9b9b9;
}
td {
  padding: 10px;
  border: 1px solid #b9b9b9;
}
@media screen and (max-width: 640px) {
  .scroll_table {
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
  }
  .scroll_table th, .scroll_table td {
    white-space: nowrap;
  }
  .scroll_table::-webkit-scrollbar {
    height: 15px;
  }
   .scroll_table::-webkit-scrollbar-track {
    background:#AFD5F9;
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
  }
  .scroll_table::-webkit-scrollbar-thumb {
    border-radius: 7.5px;
    background:#95A9BF;
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
  }
}

サンプル

以下は Bootstrap3 のレスポンシブテーブルのスタイルの一部抜粋です。

/* Bootstrap v3.3.7 のレスポンシブテーブルの例 */
.table-responsive {
  min-height: .01%;
  overflow-x: auto;
}
@media screen and (max-width: 767px) {
  .table-responsive {
    width: 100%;
    margin-bottom: 15px;
    overflow-y: hidden;
    -ms-overflow-style: -ms-autohiding-scrollbar;
    border: 1px solid #ddd;
  }
  .table-responsive > .table {
    margin-bottom: 0;
  }
  .table-responsive > .table > thead > tr > th,
  .table-responsive > .table > tbody > tr > th,
  .table-responsive > .table > tfoot > tr > th,
  .table-responsive > .table > thead > tr > td,
  .table-responsive > .table > tbody > tr > td,
  .table-responsive > .table > tfoot > tr > td {
    white-space: nowrap;
  }
}    
左端カラムを固定

以下のテーブルのように左端のカラムを固定する方法の例です。CSS と HTML で実現する方法と jQuery を使って実現する方法があります。

調べてみると色々な方法がありますが、この例では左側のカラムのみを持つテーブルを作成して、それを絶対配置することで左端のカラムが固定されているように見えるようにしています。

table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data

CSS と HTML

以下が HTML と CSS です。

HTML のマークアップは、前述のスクロールバーを表示する例と同じ scroll_table というクラスで table 要素を囲んだ div 要素に続けて、fixed_head というクラスを付けた左端の列のみを記述した table 要素を配置しています。

そしてこれらを table_outer というクラスを付けて dvi 要素で囲んでいます。この div 要素は 2つの table 要素の基点とするためのものです。

CSS で fixed_head というクラスを付けた table 要素を table_outer という dvi 要素を基点に絶対配置することで、2つのテーブルを重ねて表示して、この列が固定配置されてるように見せかけています。

<div class="table_outer">
    <div class="scroll_table">
      <table>
        <tr>
          <th>table head </th>
          <td>table data</td>
          <td>table data</td>
          <td>table data</td>
          <td>table data</td>
        </tr>
        <tr>
          <th>table head</th>
          <td>table data</td>
          <td>table data</td>
          <td>table data</td>
          <td>table data</td>
        </tr>
        <tr>
          <th>table head</th>
          <td>table data</td>
          <td>table data</td>
          <td>table data</td>
          <td>table data</td>
        </tr>
      </table>
    </div>
    <table class="fixed_head">
      <tr>
        <th>table head </th>
      </tr>
      <tr>
        <th>table head</th>
      </tr>
      <tr>
        <th>table head</th>
      </tr>
    </table>
  </div>  

左端1列のテーブル .fixed_head では、position: absolute を指定して絶対配置にしています。また、.table_outer を基点とするために、position: relative を指定しています。

スクロールバーを表示するスタイルは省略しています(前述の項を参照ください)。

※絶対配置する左端1列のテーブルには、背景色を指定する必要があります。背景色がないとスクロールする際に下の元のテーブルが透けて見えてしまいます。

.fixed_head {
  position: absolute;
  top: 0;
  left: 0;
}
.table_outer {
  position: relative;
}

jQuery を利用

前述のように HTML に追加のテーブルを記述することもできますが、jQuery を使えば、HTML は通常のスクロールバーを表示するマークアップのままで実現できます。

但し、テーブルの構成によっては、この例の jQuery ではうまく行かない場合もあると思います。その場合はテーブルの構造に合わせて書き換える必要があります。

また、前述の CSS はそのままこの例でも使います(記述しておく必要があります)。jQuery で CSS の記述も追加することは可能です。

以下が jQuery を使う場合の HTML です。スクロールバーを表示する例と同じですが、fix_col というクラスを追加しています。

<div class="scroll_table fix_col">
    <table>
      <tr>
        <th>table head </th>
        <td>table data</td>
        <td>table data</td>
        <td>table data</td>
        <td>table data</td>
      </tr>
      <tr>
        ・・・中略・・・
      </tr>
      <tr>
        <th>table head</th>
        <td>table data</td>
        <td>table data</td>
        <td>table data</td>
        <td>table data</td>
      </tr>
    </table>
  </div>

以下が jQuery の記述です。

fix_col と言うクラスを持つ div 要素全てに対して each() を使って反復処理しています。

2行目の $head は左一列のみのテーブル要素を表す変数です。$(this) は fix_col と言うクラスを持つ div 要素です。find() でこの div 要素の内側の table 要素を検索してそれを clone() でコピーを作成し、fixed_head というクラスを付与しています。

コピーした table 要素は全ての列を持っているため、3~4行目で不要な列に該当する th, td 要素を remove() を使って削除しています。not() を使って最初の th, td 要素以外を削除しています。

5行目は、キャプションがある場合の処理です。キャプション要素は通常テーブル要素の中央に配置されますが2つのテーブルを重なる場合、追加するテーブルは1列のため配置がずれてしまいます。そのため場合によっては折り返しが発生したりと、レイアウトが崩れてしまうので、ここではキャプションの内容を空白文字1つ("&nbsp;")に置き換えています。

6行目では wrap() を使って、fix_col と言うクラスを持つ div 要素を table_outer と言うクラスを持つ div 要素で囲んで、最後に append() で左一列のみのテーブル要素を追加(挿入)しています。

$('.fix_col').each(function() {
  var $head = ($(this).find("table").clone()).addClass("fixed_head");
  $head.find("th").not(":first-child").remove();
  $head.find("td").not(":first-child").remove();
  $head.find("caption").html("&nbsp;");
  $(this).wrap($('<div class="table_outer"></div>')).append($head);
});

サンプル

display プロパティを変更

<table> 内でテーブルを構成するタグには以下のようなものがあり、それぞれのタグごとに標準で適用される display の値が定義されています。(display: table

HTMLタグ displayの値 構成されるボックス
<table> table テーブルボックス
<tr> table-row テーブルの行
<td> <th> table-cell テーブルのセル
<tbody> table-row-group 行のグループ(ボディ)
<thead> table-header-group 行のグループ(ヘッダー)
<tfoot> table-footer-group 行のグループ(フッター)
<colgroup> table-column-group 列のグループ
<col> table-column グループに属する列
<caption> table-caption テーブルのキャプション

これらの dispaly プロパティの値を変更することでレイアウトを変更することができます。

よく使われるパターンとしては、会社概要などの左側が見出しの2列のテーブルです。

<table>
  <tr>
    <th>table head </th>
    <td>table data table data table data table data</td>
  </tr>
  ・・・中略・・・
  <tr>
    <th>table head</th>
    <td>table data table data table data table data</td>
  </tr>
</table> 
table {
  border-collapse: collapse;
}
th {
  padding: 10px;
  text-align: left;
  color: #333;
  background-color: #ececec;
  border: 1px solid #b9b9b9;
}
td {
  padding: 10px;
  border: 1px solid #b9b9b9;
} 
table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data

画面幅が小さくなった場合は、縦に並べることで読みやすいレイアウトにすることができます。

td, th 要素に display:block; を指定することでブロック要素が垂直方向に配置され、縦ならびにすることができます。

ボーダーを指定している場合は、重なる部分がでてくるので調整する必要があるかも知れません。

@media screen and (max-width: 640px) {
  td, th{
    display: block;
    /*width: 100%; 必要に応じて*/
  }  
  td {
    border-top: none;
    border-bottom: none;
  } 
  table {
    border-bottom: 1px solid #b9b9b9;
  }
}
table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data
table head table data table data table data table data

:before と data- 属性の利用

以下のようなテーブルを :before と data- 属性を使ってレスポンシブに対応する例です。

Member List
Name Instruments Genre Member Since
Miles Davis Trumpet Jazz 1960
Jimi Hendrix Guitar Rock 1965
Bill Evans Piano Jazz 1959
Bob Dylan Guitar Folk 1972

画面幅が小さい場合は、以下のようにエントリーごとに表示するようにします。

Member List
Name Instruments Genre Member Since
Miles Davis Trumpet Jazz 1960
Jimi Hendrix Guitar Rock 1965
Bill Evans Piano Jazz 1959
Bob Dylan Guitar Folk 1972

以下が HTML です。<thead> と <tbody> で構成されたテーブルですが、各 td 要素に data-label 属性を指定し、:before 擬似要素を使ってそれぞれの項目のラベルとして表示します。

<table>
  <caption>Member List</caption>
  <thead>
    <tr>
      <th>Name</th>
      <th>Instruments</th>
      <th>Genre</th>
      <th>Member Since</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td data-label="Name">Miles Davis</td>
      <td data-label="Instruments">Trumpet</td>
      <td data-label="Genre">Jazz</td>
      <td data-label="Member Since">1960</td>
    </tr>
    <tr>
      <td data-label="Name">Jimi Hendrix</td>
      <td data-label="Instruments">Guitar</td>
      <td data-label="Genre">Rock</td>
      <td data-label="Member Since">1965</td>
    </tr>
    <tr>
      <td data-label="Name">Bill Evans</td>
      <td data-label="Instruments">Piano</td>
      <td data-label="Genre">Jazz</td>
      <td data-label="Member Since">1959</td>
    </tr>
    <tr>
      <td data-label="Name">Bob Dylan</td>
      <td data-label="Instruments">Guitar</td>
      <td data-label="Genre">Folk</td>
      <td data-label="Member Since">1972</td>
    </tr>
  </tbody>
</table>    

以下が CSS です。1行目~14行目は画面幅が641px 以上の場合のスタイルの指定です。

画面幅が640px以下の場合は、thead 要素を画面の外に配置して非表示にしています。display:none を使って完全に非表示にしてしまうと、thead に記述されている項目(ラベル)が認識されないのでアクセシビリティに問題が生じてしまいます(ラベルが読み上げられない)。

また、tr, td 要素をブロックレベル要素に変更しています。

31~34行目では、:before 擬似要素とその content プロパティを使って data-label 属性の値をラベルとして表示するようにしています。(但し、:before 擬似要素で挿入したラベルは、HTML としては認識されず、読み上げられません)

※アクセシビリティを考慮する場合、data-label 属性の代わりに aria-label 属性を使うともっと良いかも知れません。その場合は、thead 要素を display:none を使って非表示にしても問題はないと思われます。(未確認)

table {
  border-collapse: collapse;
}
th {
  padding: 10px;
  text-align: left;
  color: #333;
  background-color: #ececec;
  border: 1px solid #b9b9b9;
}
td {
  padding: 10px;
  border: 1px solid #b9b9b9;
}
@media screen and (max-width: 640px) {
  thead {
    position: absolute;
    top: -9999px;
    left: -9999px;
  }
  tr {
    display: block;
    margin-bottom: 5px;
  }
  td {
    display: block;
    text-align: right;
    min-width: 280px;
    background: #FCFCFC;
  }
  td:before {
    content: attr(data-label)": ";
    float: left;
  }
  td:not(:last-child) {
    border-bottom: none;
  }
}

テーブルの縦横を入れ替える方法

以下のような <thead> と <tbody> で構成されたテーブルの場合、比較的簡単に縦横を入れ替えることができます。

以下が基本的なテーブルの HTML と CSS(大画面の場合)です。

18,19 行目、 25,26 行目、32,33 行目のコメントアウトは、タグを改行することで半角スペース分の隙間が挿入されるのを防ぐための記述です。別の方法としては、tr の閉じタグ </tr> を省略しても同じ効果が得られます。

<table>
  <thead>
    <tr>
      <th>table head1</th>
      <th>table head2</th>
      <th>table head3</th>
      <th>table head4</th>
      <th>table head5</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>table data 1-1</td>
      <td>table data 2-1</td>
      <td>table data 3-1</td>
      <td>table data 4-1</td>
      <td>table data 5-1</td>
    </tr><!-- 
 --><tr>
      <td>table data 1-2</td>
      <td>table data 2-2</td>
      <td>table data 3-2</td>
      <td>table data 4-2</td>
      <td>table data 5-2</td>
    </tr><!-- 
 --><tr>
      <td>table data 1-3</td>
      <td>table data 2-3</td>
      <td>table data 3-3</td>
      <td>table data 4-3</td>
      <td>table data 5-3</td>
    </tr><!-- 
 --><tr>
      <td>table data 1-4</td>
      <td>table data 2-4</td>
      <td>table data 3-4</td>
      <td>table data 4-4</td>
      <td>table data 5-4</td>
    </tr>
  </tbody>
</table>    
table {
  border-collapse: collapse;
}
th {
  padding: 10px;
  text-align: left;
  color: #333;
  background-color: #ececec;
  border: 1px solid #b9b9b9;
}
td {
  padding: 10px;
  border: 1px solid #b9b9b9;
}

以下のようなテーブルになります。

table head1 table head2 table head3 table head4 table head5
table data 1-1 table data 2-1 table data 3-1 table data 4-1 table data 5-1
table data 1-2 table data 2-2 table data 3-2 table data 4-2 table data 5-2
table data 1-3 table data 2-3 table data 3-3 table data 4-3 table data 5-3
table data 1-4 table data 2-4 table data 3-4 table data 4-4 table data 5-4

画面幅が狭い時には、テーブルの縦横を入れ替えてスクロールバーを表示するようにします。

thead 要素に float: left を指定して、tbody 要素の左に回り込ませて横に並べます。

thead 要素内の th 要素に display:block を指定し、ブロック要素にして垂直方向に配置します。

tbody 要素内の tr 要素に display:inline-block を指定して横に並べます。

tbody 要素内の td 要素に display:block を指定し、ブロック要素にして垂直方向に配置します。

スクロールバーを表示するため、tbody 要素に overflow-x: auto を指定しています。(13行目)

@media screen and (max-width: 640px) {
  table {
    display: block;
    position: relative;
  }
  thead {
    display: block;
    float: left;
  }
  tbody {
    display: block;
    position: relative;
    overflow-x: auto;
    white-space: nowrap;
  }
  thead th {
    display: block;
  }
  tbody td {
    display: block;
  }
  tbody tr {
    display: inline-block;
  }
  th:not(:last-child) {
    border-bottom: none;
  }
  td:not(:last-child) {
    border-bottom: none;
  }
  td {
    border-left: none;
  }
}

幅の狭い時は以下のような表示になります。

table head1 table head2 table head3 table head4 table head5
table data 1-1 table data 2-1 table data 3-1 table data 4-1 table data 5-1
table data 1-2 table data 2-2 table data 3-2 table data 4-2 table data 5-2
table data 1-3 table data 2-3 table data 3-3 table data 4-3 table data 5-3
table data 1-4 table data 2-4 table data 3-4 table data 4-4 table data 5-4

サンプル