レスポンシブ対応時に知っていると得する（かもしれない）知識

# はじめに

今やレスポンシブ対応は、要件としてデフォルトで求められるケースも増えてきました。きちんと作ろうとすると結構手間が掛かりますよね。。。

ちょうど機会があり、色々と調べていたら知らなかったことも多く、私の脳みそのメジャーバージョンがアップデートされました。今回、その中でも「これは覚えておきたい！」と思ったことをまとめてみました。何かの参考にでもなれば幸いです。

実際に使うかどうかはさておき、こういったものがあるのかと知っておくだけでも役に立つかもしれません。知っているものばっかりだったらｺﾞﾒﾝﾈ





# 目次
- html編
  - htmlのみで「使用するメディアの切り替え」方法を知る
- css編
  - フォントサイズremという単位を知る
  - メディアクエリにpx指定したときの動作を知る
  - viewportの単位: vw, vh, vmin, vmaxを知る
- javaScript編
  - ブレークポイントの設定方法を考える
- 終わりに





# html編
## htmlのみで「使用するメディアの切り替え」方法を知る

レスポンシブデザインは、ワンソースでデバイスサイズに応じたレイアウトを実現できるのが強みです。一方でスマホには不要な要素もまとめて読み込むため無駄も発生しがちです。

今までは（きちんと考慮する場合）サーバサイドやJSで読み込むデータを制御するのが一般的だったかと思いますが、htmlのみで最適化させる方法があります。


## pictureタグでメディア自体を切り替える

`<picture>`と`<source>`タグを使うことで、異なるメディアをviewportに応じて使い分けることができます。**アートディレクション** と呼ぶこともあるようです

- [対応状況: can i use](http://caniuse.com/#search=picture)
- 使用するメディアのダウンロード（リクエスト数）が一度で済みます

```picture.html
<picture>
  <source media="(max-width: 320px)" srcset="img/320.gif">
  <source media="(max-width: 640px)" srcset="img/640.gif">
  <img src="img/640.gif" alt="">
</picture>
```

**[動作イメージ]** 

![picture-anim.gif](https://qiita-image-store.s3.amazonaws.com/0/58436/ec1528b1-7c3a-e8f2-ed3e-bb00970bc26c.gif)



> リサイズの度にメディアがリクエストされるようですが、あまりそんな使い方はしないとも思うので許容範囲でしょうか（chrome v49で確認）。




## imgタグにsrcsetで画像のサイズ（解像度）を切り替える

1つの画像のサイズ（解像度）をviewportに応じて切り替えることができます。アートディレクションが不要でサイズのみ変更したいというケースで使用するのが良さそうです。

- [対応状況: can i use](http://caniuse.com/#search=srcset)
- 画像のダウンロード（リクエスト数）が一度で済みます

使用される画像の選択はブラウザ側で判断されます。例えばcacheにより意図通りに切り替わらない（cacheの方が優先される）こともあります。そういった意味でも、基本的には同じ画像のサイズ違いを扱うのが無難そうです。


```srcset.html
<img src="img/1000.gif" srcset="img/1000.gif 1000w, img/640.gif 640w" sizes="50vw">
```

> **参考サイト**
> [srcsetとsizes](http://terkel.github.io/srcset-sizes/)





# css編
## フォントサイズremという単位を知る

**rem** という単位があります。これは、**root+em** という意味です。

- [対応状況: can i use](http://caniuse.com/#feat=rem)
- root＝html要素からの相対的なサイズが設定されるため、階層が変わっても影響がない
  - `em`の場合は親に影響される
- IEなどの文字サイズ変更機能を使うには、rootのfont-sizeは%指定する
  - rootをpx指定すると、remでも変更できなくなった
- rootを62.5%（10px相当）にすると、remでの計算が楽
  - 1.4rem = 14px相当

rootのフォントサイズを10px以外、もしくはfallbackを考慮する場合には、sassのmixinが便利です。

> fallbackにはpleeeaseで対応することもできます。
> http://pleeease.io/docs/


```rem.scss
$g_base-font-size-px: 14px;
$g_base-font-size-percent: ($g_base-font-size-px / 16px * 100) + 0%; // 16pxはブラウザの文字サイズ初期値=100%

@mixin rem($size-px: $g_base-font-size-px) {
  font-size: $size-px;
  font-size: ($size-px / $g_base-font-size-px) * 1rem;
}

html {
  font-size: $g_base-font-size-percent;
}
div {
  @include rem(12px);
}
```

```rem.css
// compile
html {
  font-size: 87.5%;
}
div {
  font-size: 12px;
  font-size: 0.85714rem;
}
```





## メディアクエリにpx指定したときの動作を知る

メディアクエリをpxで指定していると、ブレークポイントは絶対的な値になります。具体的には、ユーザがブラウザでのフォント設定をデフォルト以外に設定していた場合でも、ブレークポイントは変動しません。

そのため、フォントサイズによって適切なレイアウトを提供したい場合は、**em** での指定が良さそうです。

> **参考サイト**
> [[CSS]Media Queriesで使う単位はpx, em, remのどれが適しているか検証 -px指定は注意が必要](http://coliss.com/articles/build-websites/operation/css/media-query-units.html)




## viewportの単位: vw, vh, vmin, vmaxを知る
viewportを基準としてサイズを決める単位が存在します。
今まで面倒だったスタイルを、さくっと実現できるかもしれません。

| 単位 | 概要 |
|:---|:---|
| vw | viewportの幅の1/100 |
| vh | viewportの高さの1/100 |
| vmin | viewportの幅or高さの小さい方の1/100 |
| vmax | viewportの幅or高さの大きい方の1/100 |

- [対応状況: can i use](http://caniuse.com/#feat=viewport-units)
- vmin, vmaxは中々使いどころが難しいかもしれません


### **%** との使い分け

**横幅いっぱい→100%**
vwはスクロールバーを含むため、html要素より大きくなる場合がある

**高さいっぱい→100vh**
vhはどこに配置されてもviewportと比較してサイズが決まる


> **参考サイト**
> [[CSS]ビューポート(vw, vh)とパーセント(%)、レスポンシブに適した単位の賢い使い分け方法](http://coliss.com/articles/build-websites/operation/css/viewport-vs-percentage-units-by-ire.html)





# javaScript編
## ブレークポイントの設定方法を考える

JS内でもサイズによって処理を分けたいというケースは多いかと思います。
以下のような設定方法が考えられるでしょうか。

1. ユーザーエージェントなどデバイス単位で振り分ける
2. CSS側のメディアクエリでフラグを立て、JS側ではそこを見るだけ
3. CSSとは別に、JS単体で判断する

> ※1については省略

## CSS側のメディアクエリでフラグを立て、JS側ではそこを見るだけ
例えば、以下のようにCSS側で各サイズごとのスタイル（フラグ）を設定します。
そしてJS側では単純にスタイルで判断するだけにするとCSS側との差異もなくなり、ブレークポイントの値がCSSで一元管理できます。

```check-js.html
<div id="js-check-sp" class="check-size is-sp"></div>
<div id="js-check-tablet" class="check-size is-tablet"></div>
<div id="js-check-pc" class="check-size is-pc"></div>
```

```check-js.check
.check-size {
  display: none;
  background-color: #eee;
}

@media screen and (max-width: 400px) {
  .check-size.is-sp {
    display: block;
  }
}
@media screen and (min-width: 400px) and (max-width: 1000px) {
  .check-size.is-tablet {
    display: block;
  }
}
@media screen and (min-width: 1000px) {
  .check-size.is-pc {
    display: block;
  }
}
```

```check-js.js
var size = {
  isSp: function() {
    return $('#js-check-sp').is(':visible');
  },
  isTablet: function() {
    return $('#js-check-tablet').is(':visible');
  },
  isPc: function() {
    return $('#js-check-pc').is(':visible');
  },
};
console.log('sp: ' + size.isSp());
console.log('tablet: ' + size.isTablet());
console.log('pc: ' + size.isPc());
```

> - 実際には空のdivでなく、ちゃんとした要素で行った方が良いかと思います
> - もしくはcontentプロパティを使うとか、色々とやりようはあると思います



## CSSとは別に、JS単体で判断する

実際に横幅を計ってJS単体で判断することができます。
ただしメソッドによっては、ブラウザやバージョンによって返ってくる値が異なる可能性がありますので、注意が必要です。

| メソッド | 備考 |
|:---|:---|
| $(window).width() | スクロールバーの幅が含まれないため、メディアクエリとのサイズがズレる可能性あり。バー幅も考慮が必要 |
| window.innerWidth | IE9以上。ただし実行のタイミング（？）か、iOSで980pxという値が返ってくる場合があり |
| window.screen.width | モニターの解像度を返す（動かない端末・環境もあるかも） |
| window.matchMedia | IE10以上。CSSのメディアクエリと同じようにmax-width:などで指定可 |

matchMediaはメディアクエリのためのメソッドで、かつaddListenerでリスナーを設定することもできます。
未対応ブラウザ用に`matchMedia.js`というプラグインもあるようです。


```check-breakpoint.js
var breakPoint = 414;
var isSp = function(){
  if (!window.innerWidth){
    return false;
  }
  // IE9以下 or メディアクエリメソッドが使えない場合はinnerWidthで判定
  if(!window.matchMedia){
    return (window.innerWidth <= breakPoint) ? true : false;
  }
  // メディアクエリメソッドで判定
  if(window.matchMedia('(max-width:'+breakPoint+'px)').matches){
    return true;
  } else {
    return false;
  }
}
```




# 終わりに

正直レスポンシブ対応は面倒ですが、こういった知識を上手く活用してコンテンツのクオリティを保ちたいものですね。