「レスポンシブ」って単語を知らない人でも、ウィンドウをウィンウィンさせてコンテンツがついてくるのを見せながら「こういうのがやりたいんですよね~」とか言っちゃうアレです。
どんなデバイスで見てもいい感じになるようにしろって意味で使われますけど、iPhoneですら1サイズじゃなくなったこのご時世ですよ、面倒な割に気軽に頼まれがちじゃない?
スマホが出だした頃はPC/SPの2パターンあれば満たされたのが、今は…………🙄
何種類あるかわからない端末に毎年増える解像度、そんなカオスな表示環境にどうやって対応するのよ????????
とまぁ毎年苦しめられた結果、色々と知見が増えたのでこれまでに調べたり使ったりした「レスポンシブ」を実装するための方法をまとめました。
最初に確認(決定)すること
ブラウザ・端末の対応範囲
大事なことなのでめったに使わない赤字にした。
最新2バージョン以内のモダンブラウザ限定なら、レスポンシブ対応はナウいテク盛りだくさんで実装出来るからフロントドカタ的には大変ワクワクする仕事になるのだが、逆ならマジ苦行なので相応の覚悟がいる。(これも大事なので太字にした)
レスポンシブ対応で盛大に足を引っ張る以下の悪魔をサポートするかしないかで実装難易度が天地の差になってくる。
- IE11
- IE10以下
- Edgeの古いやつ
- Android4系
- Android5系
- Android6系
- 4インチ端末
2019年現在の切り捨て推奨は太字にしたやつです。
IE10以下はもう死んでると世間的に認知されてるので切ることに同意を得やすいが、IE11は中途半端に生を長らえたゾンビであるため切ることに反対する声も根強く残っている。
IE11だけが対応してないものがあまりに多すぎるので、IE11の扱いをどうするかは堅く決めておきたいところ。IE11の扱いが決まれば10以下も自ずと決まるよね。
Android4系も未だしぶとく生き残って…いやもう死んだかな流石に。OSバージョンアップが不可能な旧端末が多いので同じく要注意です。
どれだけ未対応なのかは IE11とAndroid4系のサポートを終わらせるための HTML/CSS/JS 未対応仕様まとめ にまとめました。
発売年月が古いものは端末の処理性能も低いです。iPhoneは4年、Androidは3年で切るくらいの気持ちでいたほうが幸せになれます。
4インチ端末は幅320pxです。根強いファンが多く、街中歩いてると結構使ってる人を見るので切るのはまだ難しいと思う。
320px画面では375px基準で作られたものは100%はみ出すと思ったほうがいいです。
フリーランスの人なら上記への対応は特別料金徴収したらいいと思います。決めたらリリースまで壁に貼っておこう。
デザイナーへお願いしておくこと
Webデザインに特化して情報を追ってなければ、レスポンシブなんてなんのこっちゃだろうから意味不な顔されるのは仕方ないです。まずは同じ地獄への道を歩んでいく仲間として労いの言葉でもかけておこう。
これまで私はPC向けとSP向けの2パターンデザインを渡されて「レスポンシブで」と言われる状況で「中間はどうするんや…」と思う現場しかなかったけど、色々作ってみると予めデザイナーに考えておいて欲しい要所さえ抑えてあれば2パターンでもどうにかなるんで、以下に書き出してみました。
a.デザインサイズの決定
2パターンなら、最低限
モバイル端末はRetina対応を基本として、iPhone基準の 750px。
デスクトップは1200px。
が、あればどうにかなります。
ブレークポイント分作るぜ!と意識高まってるデザイナーなら、
Bootstrapとか Bulmaとか UIkitとかの設定を参考に
調整してもらう。
決めたサイズは共有する。そしてブレークポイントなどに利用する。
つまりSassやらLessやらCSSVariablesやらで変数を作成しておく。
b.ピクセル比で割り切れない数字を使用しない
Retina向けのデザインを750pxで作ったとして、デザイン上199pxの画像は画面上では1/2になって99.5pxになるけど、端数の0.5pxはどうなるでしょう?
これは端末のピクセル比によって見え方が変わり、ボケたり隙間ができたりといった描画上の問題が発生する。
脳死したいなら4の倍数で展開しとけばいいと思う。
ブラウザでピクセル比はwindow.devicePixelRatioプロパティにあるのでJavaScriptで取得できます。
ざっくりいうと、
一般的なPC用モニタやノートPCは1倍、5KやMBPなど2倍のやつもいる。
最新のスマホやタブレットは3倍。4倍のもいる。一般的なモバイル端末は2倍。
という感じ。
c. 4インチと4Kについて
モバイル端末でスマホを下限とするなら、実質4インチが最小なのでW320px(デザイン上でW640px)。
360pxや375px基準でデザインされたものは320pxにそのまま対応できないことが多い。
デスクトップの場合、一般的に普及してるのはフルHDの1920×1080pxで、最大は4Kモニターの3840x2160px。
ブラウザUIがあるのでwindow.innerHeightは100pxほど小さくなるものの、3840x2000pxまでブラウザ広げて見られる環境があるということです。
うちのウルトラワイドモニタでは、Chromeフルスクリーンで 2560x1080pxありました。(ブラウザをフルスクリーンにすること無いからせいぜい1200px程度です)
余り一般的ではないけど、iMac Proの5Kは 2560x1440pxのRetinaで5120x2880pxもあります。とんでもねえ…。
ざっくりどんなサイズがあるかを見たいなら、
Material DesignのDevice Metricsとか、SCREEN SIZ.ESとかが便利。
STFの端末リストも解像度とか出るからこういう一覧にできる。
最低限、
「4インチ端末で見られたときどうするのか」
「1800pxを超えるウィンドウサイズで見られたときどうするのか」
をデザイナーに考えてもらう。
d. 画像についての決め事
レスポンシブは無限に書き出す画像が増えていくので、先に以下のことを決めておいた方が良い。
- 画像の命名ルール
ケバブケースなのかキャメルケースなのか、アンダースコアはどう利用するのか - ピクセル比別の命名ルール
Photoshopだと@2x がデフォなので特にこだわりなかったらこれでいいと思われ - 状態が違うものの命名ルール
ボタンの active, hover みたいなやつ - コンポーネントの命名ルール
人によって呼び方違うやつはブレやすい(modalとdialogとか) - 連番のルール
0つけるのかつけないのか、1スタートなのか0スタートなのか
あと、デザイナーがやりがちだけどフロントドカタ的にはやってほしくない系のあれこれも事前にお願いしておく。
- img_みたいな接頭語は不要(ディレクトリと同じ接頭語も付けない)
- 透明部分がないやつをPNG24にしない
- 複数枚重ねて使う画像は幅と高さと中央線を揃える
- インタラクションがあるUIの画像は状態変化後の画像も必要(ボタンとか)
- メタ情報は不要
e. フォントとフォントサイズ
- Web Fontsを使う場合は別として、ブラウザだと端末にインストールされているフォントでの表示になる。
- ユーザーがフォントをカスタムしていることがある
- AndroidはBoldができない
- Androidにはヒラギノ角ゴが入ってない
…みたいな、仕様上どうしようもないことについてはデザイン前に確認。
フォントサイズはデザイン上での指定を必ずPixelにしてもらう。
ptとpxではサイズが異なる(1px = 約1.333pt)のでptのままだと誤解が生じる。
文字にかかるアンチエイリアスについてはWindowsとMacで仕様が異なるので、アンチエイリアスの有無により読みにくくなってないか確認が必要。
f. Adobe XD・Sketch・Figmaの利用
できればPhotoshopではなくAdobe XD、Sketch、Figmaあたり使ってもらうと良き…です。
それでコンポーネントやアセットを意識してデザインしてもらえれば、プロトタイピングも捗って世界が変わるのです。
(参考:Photoshop CCからFigma(プロライセンス版)に乗り換えている件)
プロトタイピングツールは内臓機能を使ってもいいしZeplinやInVisionのようなサービスを使ってもいい。
が、我々ドカタにもお気に入りのエディタがあるように、デザイナーにも手に馴染んだお気入りのデザインツールがあるだろうから「できれば」で。
画像の書き出し
書き出す画像の種類は、最低限等倍と2倍が必要。
3倍以上は少しでもぼやけさせたくないものを優先する。
UIで使う画像はなるべくSVGを利用する。
細かなアイコンはWebFontにしてしまうと利便性がよくなる。
FontAwesomeのような完成品使うもよし、icomoonとかで自作するもよし
Photoshop
画像アセット機能をオン、レイヤー名で指定
image.png, 200% image@2x.png, 300% image@3x.png
見栄えはよろしくないが、これで3倍まで一括で生成される。
その他のレイヤー名によるオプション指定はAdobeのブログを参照。
WordPress
WordPressが内蔵してる画像自動生成機能ってすごい便利だと思う。
画像管理をWordpressに丸投げしてREST APIで内容引っ張るのもありじゃない?
[WordPress] REST APIで静的サイトに更新可能なコンテンツを作成する
Responsive Image Breakpoints Generator
ブレークポイントの設定に基づいて画像生成してくれるジェネレータ。
Pictureタグまで添えてくれるから少量使いなら便利なんだけど、
大量に画像がある場合にこれで1枚1枚やるのは苦行がすぎるので、
CDN配信までがセットになっている大本のCloudinary APIを利用するのが良いと思う。
Unsplash
写真素材サービスだが、APIとかURLのオプションでサイズの調整とかが思うがままできるので、ネイルサロンやヘアサロンなど写真をそのまま利用するサイトを作るときには便利かも。
OPTPiX imésta
画像圧縮と生成の最強ツールはこれ。ただし1年30万というライセンス料がかかるソフトウェアである。ゲームみたいな画像を主としたアプリを作る目的に向けた製品なのでWeb用途にはハイスペックすぎるかもしれないが、参考に。
HTML
Viewportの設定
端末の横幅に合わせてレンダリングしてくれよな!という指定。
これがないとモバイル端末で表示したときめっちゃ縮小されてしまう。
HTMLのheadタグ内に記載する。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
Link要素のmedia属性によるCSSファイルの変更
以下の例は印刷の時と600pxまでの幅の画面で表示した時に専用のスタイルシートを設定する例。
hrefで指定したCSSファイルはmedia属性の条件がtrueになった場合のみ読み込まれる。
<link href="print.css" rel="stylesheet" media="print"> <link href="mobile.css" rel="stylesheet" media="screen and (max-width: 600px)">
CSS
主な単位
CSSのlengthデータ型は、相対指定と絶対指定で使える単位が変わる。
相対指定
相対的な長さとは、他の長さに従って長さを指定することです。単位によって、これは特定の文字の寸法であったり、行の高さであったり、 viewport の寸法であったりします。絶対指定
出力メディアの物理的な特性が分かっている場合(印刷レイアウトなど)に物理的な長さを表します。これはある単位を物理的な単位に固定してから、これを基準に他の単位を定義します。
スクリーン向けCSSには相対指定の単位、印刷用CSSは絶対指定の単位…みたいな使い分けができる。
各単位の特性を覚えてないと、実装中に詰まることがあると思います。
単位 | 種類 | 説明 |
---|---|---|
px | 絶対 | モニターの画素(pixel)を1とする単位。 印刷や高解像度モニターでは1pxが端末の複数ピクセルに変わることがある |
pt | 絶対 | 1ポイント。 1pt = 1in の1/72 |
cm | 絶対 | 1センチメートル。 1cm = 96px/2.54 |
mm | 絶対 | 1ミリメートル。 1mm = 1cm の1/10 |
% | 相対 | 親要素の幅または高さを基準とする単位 |
em | 相対 | その要素のfont-sizeを基準とする単位。 font-size プロパティ自身に使われた場合は、要素に継承されたフォントの大きさを表す。 |
rem | 相対 | ルート要素(普通はhtml)の font-size(大抵のブラウザの既定値は16px)を基準とする単位。 ルート要素の font-size で使うと初期値を表す。 |
vw | 相対 | ビューポートの初期値の包含ブロックにおける幅の1%と同じ |
vh | 相対 | ビューポートの初期値の包含ブロックにおける高さの1%と同じ |
メディアクエリ(CSS Media Queries)
前述のmedia属性もこれですが、とにかくメディアクエリを知らないことにはレスポンシブ対応はできないと言っても過言ではない。
よくわからない人向けに一から説明してると超長くなるんで、MDNのメディアクエリの使用を読むなり、ググるなりして理解できるドキュメントを探してください。
使い方は検索と似たようなもので、真となる条件を括弧内に書いていくだけです。
and
やor
も使えます。
/* 縦長で最大幅375pxの端末である場合、 文字色を赤に */ @media (max-width: 375px) and (orientation: landscape) { body { color: red; } }
機能クエリ(CSS Feature Queries)
機能クエリは条件として書いた機能をサポートしている場合に真となる。
backdrop-filterのような機能クエリの対応範囲よりも狭い、新しく実装された機能を使いたいときに便利です。
以下はbackdrop-filterの例:
@supports (backdrop-filter: none) { .content { backdrop-filter: blur(5px); } }
See the Pen
backdrop-filter by Tenderfeel (@Tenderfeel)
on CodePen.
その他有用な利用法についてはHow @supports Works(日本語訳記事)が参考になる。
変数の利用
一部のブラウザを除けば普通にCSS変数が利用できるので、これを使わない手はないです:
:root { --section-width: 10vw; } section { width: var(--section-width); }
混沌としがちなmarginとpaddingも、CSS変数を利用すれば相対的に指定するのが楽になります。
Create your design system, part 4: Spacing(日本語訳)を元に作ったサンプル:
See the Pen
css responsive spacing sample by Tenderfeel (@Tenderfeel)
on CodePen.
テキスト
font-sizeでremを利用する
相対指定で使える単位は%
, vw
, em
などがあります。(前述の単位についてを参照)
何を使うか迷ったらもう脳死でfont-sizeをrem
にしとけばいいです。
remが%やemと最も違うのは、remが基準とするのはhtmlの文字サイズなので直近の親要素の文字サイズには影響を受けないというところにあります。
See the Pen
Comparison of font-size specification by Tenderfeel (@Tenderfeel)
on CodePen.
逆に親要素に影響を受けさせたいならrem以外という使い分けもアリです。
remで指定しておけば文字の拡大縮小操作はhtmlのフォントサイズを変更するだけでよくなるので、メディアクエリによる操作も楽です。
See the Pen
Responsible Font-Size by Tenderfeel (@Tenderfeel)
on CodePen.
font-sizeやline-heightでcalcを利用する
Mike Riethmuller氏が2015に書いた記事Fluid typography examplesより。
画面サイズによって見やすいフォントサイズや行間は違うからcalcで計算すればいい感じになるんじゃね?
というのを表現するのが以下の式:
body { font-size: calc([minimum size] + ([maximum size] - [minimum size]) * ((100vw - [minimum viewport width]) / ([maximum viewport width] - [minimum viewport width]))); }
See the Pen
JEVevK by CSS-Tricks (@css-tricks)
on CodePen.
Geoff Graham氏が作成したSass Mixinを利用する例
See the Pen
Base Example of Fluid Type w Sass by Chris Coyier (@chriscoyier)
on CodePen.
calcを利用する場合の難点は、フォントサイズに誤差が出ることです。
画像
レスポンシブ・イメージと呼ばれるものである
CSSで相対サイズを指定する
IMGタグ等にmax-width
を利用すれば、指定した要素が親要素からはみ出さなくなる。
img, picture { max-width: 100%; }
See the Pen
max-width: 100% by Tenderfeel (@Tenderfeel)
on CodePen.
SrcsetとSizes属性の利用
SrcsetとSizes属性をIMGタグで使うと、指定したクエリに応じた画像を出し分けることができる、というものである。
Wordpressだと、レスポンシブイメージ機能をONにすることで画像出力時にIMGタグがSrcset属性つきに変換される。
<img src="jo-600x338.jpg" alt="" width="600" height="338" class="alignnone size-large wp-image-3970" srcset="jo-600x338.jpg 600w, jo-300x169.jpg 300w, jo.jpg 638w" sizes="(max-width: 600px) 100vw, 600px">
レスポンシブ実装には必須と言っても過言ではないが、Caniuseで対応状況を見ると前述のIE11やAndroid4系が未対応。
Picture要素
source要素とimg要素と併用することで、media属性やsrcset属性の条件に応じた画像を表示することができるもの。
これも現在のところIE11とAndroid4系以外はほぼ対応しているのでその2つさえ切れば素で使えます。対応するならPolyfillが必要。
以下MDNのコードサンプルを引用
<picture> <source srcset="/media/examples/surfer-240-200.jpg" media="(min-width: 800px)"> <img src="/media/examples/painted-hand-298-332.jpg" /> </picture>
Srcset属性とPicture要素どっちを使うか問題
全部Srcsetでも問題はないですが、理想は、拡大縮小だけならSrcset、そうでなければPicture、だと思います。
それを踏まえてMDNのドキュメントを読むと分かりやすい。
WebpやJPEG2000を利用する場合も、Picture要素での対応になります。
background-sizeの活用
DIV要素等にbackground-image
で背景を指定して、bakcgorund-size
をcontainやcoverにする。
するとブラウザがいい感じのサイズになるよう自動的に調整してくれるので、画像を画面いっぱいに引き延ばした背景などがお手軽に作れる。
See the Pen
background-size: cover by Tenderfeel (@Tenderfeel)
on CodePen.
object-fitによるトリミング
object-fitを使うとimgやvideo要素のリソースをどのようにはめこむかを指定できる。
See the Pen
Eqobep by Tenderfeel (@Tenderfeel)
on CodePen.
object-fitを使わない場合は、background
かdiv>img
で複雑なCSSを指定しないと実装できません。
ライブラリの利用
未対応ブラウザにも対応させるとなるとJavaScriptを利用するしかない。
Picturefill
https://github.com/scottjehl/picturefill
2013年に登場、最も有名なpictureのpolyfillライブラリ。仕様通り書くだけでおkなので使いやすい。
<!-- Using the `srcset` & `sizes` attributes --> <img sizes="(min-width: 40em) 80vw, 100vw" srcset="examples/images/medium.jpg 375w, examples/images/large.jpg 480w, examples/images/extralarge.jpg 768w" alt="…"> <!-- Using the `picture` element --> <picture> <!--[if IE 9]><video style="display: none;"><![endif]--> <source srcset="examples/images/extralarge.jpg" media="(min-width: 1000px)"> <source srcset="examples/images/large.jpg" media="(min-width: 800px)"> <!--[if IE 9]></video><![endif]--> <img srcset="examples/images/medium.jpg" alt="…"> </picture>
Lazysizes
https://github.com/aFarkas/lazysizes
遅延読み込みとレスポンシブイメージ機能をサポートしているライブラリ。
対応ブラウザは document.getElementsByClassName
が使えるもの全て、なのでIE8以外である。
data属性によりsrcsetやsizesを指定すると画面サイズに最適な画像を表示する。
<!-- responsive example with automatic sizes calculation: --> <img data-sizes="auto" data-src="image2.jpg" data-srcset="image1.jpg 300w, image2.jpg 600w, image3.jpg 900w" class="lazyload" /> <!-- responsive image with the picture element --> <picture> <!--[if IE 9]><video style="display: none"><![endif]--> <source data-srcset="500.jpg" media="(max-width: 500px)" /> <source data-srcset="1024.jpg" media="(max-width: 1024px)" /> <source data-srcset="1200.jpg" /> <!--[if IE 9]></video><![endif]--> <img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="1024.jpg" class="lazyload" alt="image with artdirection" /> </picture>
Imager.js
https://github.com/BBC-News/Imager.js
BBCニュースが自社サイトで使うために開発したライブラリ。遅延読み込みにも対応。
こちらは画像1枚ごとにインスタンス作成が必要で、サイズ等の情報はJS側で設定する。
<div style="width: 240px"> <div class="delayed-image-load" data-src="http://example.com/assets/{width}/imgr{pixel_ratio}.png" data-alt="alternative text"></div> </div> <script> new Imager({ availableWidths: [200, 260, 320, 600], availablePixelRatios: [1, 1.3, 2] }); </script>
レイアウト
とりあえず種類はこれくらいありますね…
- テーブルレイアウト
コンテンツの枠組みをtable要素でこしらえる古典的手法。
そもそもデータじゃないものにtable使うのは間違っているので邪道だったが、あの頃は難しいデザインも崩さずに組めると重宝されていたのじゃよ…。 - ソリッドレイアウト
別名固定レイアウト。コンテンツの枠組みの横幅を固定した値(px, emなど)で指定する手法。
画面幅を変えてもコンテンツの表示領域は変化しないので表示崩れが起きにくい。 - エラスティックレイアウト
コンテンツの枠組みの横幅を文字サイズの値(em, rem)で指定する手法。文字サイズの拡大縮小でコンテンツのサイズも変わる - リキッドレイアウト
別名可変レイアウト。コンテンツの枠組みの横幅を割合の値(%、vwなど)で指定する手法。
画面サイズ変更でコンテンツの表示サイズが変化する。 - フレキシブルレイアウト
リキッドをベースにコンテンツの配置そのものまで変更する手法。
CSS Flexible Box Layout Moduleを指す場合もある
まあ画面サイズ変わった時にいい感じに収まるならどれ使ってもいいんですよ。
前の画像で上げたmax-width:100%
にするやつはリキッドレイアウトの一例です。
CSS Flexible Box Layout Moduleによる3カラムレイアウトの変更例
display:flex
で各要素を配置、メディアクエリで操作する例です。
サンプルは600px以下で縦並びになります。
See the Pen
3 Column Flexbox Layout Sample by Tenderfeel (@Tenderfeel)
on CodePen.
CSS Grid Layout Moduleによる3カラムレイアウトの変更例
display: grid
で各要素を配置、メディアクエリで操作する例です。
サンプルは600px以下で縦並びになります。
See the Pen
3 Column Grid Layout Sample by Tenderfeel (@Tenderfeel)
on CodePen.
グリッドとフレキシブルボックスどっちを使うか問題
MDNのドキュメントに説明があります:
CSS グリッドレイアウトとCSS フレックスボックスレイアウトの基本的な違いは、フレックスボックスは一次元 – 一列又は一行 – のレイアウトのために設計されたという点です。グリッドは二次元 – 行と列が同時 – のレイアウトのために設計されました。
やれることが似てるし、「これはGridでなければいけない」みたいな決まりは特にないんで、指定された見た目が綺麗に実装できる方法を選んでます。
判断材料の1つとしては、何行になるかわからないものを左詰めで並べようとする例が分かりやすいと思います:
See the Pen
3 Column Flexbox Layout Sample by Tenderfeel (@Tenderfeel)
on CodePen.
要素が足りない行があったとき、フレキシブルボックスだと左詰にする方法が存在しないので表示崩れを起こします。
これを解決するには不足している要素をJavaScriptで追加するなどの操作が必要です。
代わりにグリッドを使うと、綺麗に左詰で並べることができます。
paddingによる高さの相対指定
たとえば親要素の幅に応じて可変する16:9のスペースが欲しいってなったとき、 heightで%を使っても反映されない。
vwやvhを使うと一見うまく相対指定できるように見えるものの、画面サイズに対する相対なので、親要素の幅が変わった時高さが狂います。
子要素の高さを親要素の幅に追従させたいとき、使えるのがpadding
での相対指定:
See the Pen
padding-top spacer by Tenderfeel (@Tenderfeel)
on CodePen.
beforかafter擬似要素にpadding-top
かpadding-bottom
を指定すれば、親要素の幅を基準とした高さに広げることができる。
padding-top:56.25%
=16:9になります。覚えておくと便利。
便利ツール
- CSS3 Media Queries Generator
その名の通りメディアクエリの生成機 - responsivebreakpoints.com
うpした画像から自動的に各種サイズに縮小したコピーを生成、かつimgタグやpictureタグのソースまでこしらえてくれるレスポンシブ画像ジェネレーター - Layoutit!
グリッドレイアウトのビジュアルエディター - CSS unit conversion
CSSの単位ごとの変換状況を比較できる - PxtoRem
pxからremへの変換を一括でやってくれるChrome機能拡張
「レスポンシブWebデザインを実装するためのTips」への1件のフィードバック