画像のimgタグのsrcset属性によるレスポンシブ配信

自分の写真結城永人 -

サイトの画像をデバイス毎に振り分けてレスポンシブに表示するにはimgタグにsrcset属性でそれぞれの画像URLを設定するのが簡単だ。

山の頂上の岩に座っている人の後ろ姿

imgタグのsrcset属性のマークアップ

imgタグはそのままで、srcset属性を特定の仕方で値を付けて追加する。

画像を画面幅で切り替える場合

<img src="基本の画像URL" srcset="モバイル向け画像URL 640w, デスクトップ向け画像URL 1280w" sizes="(max-width:1280px) 100vw, 1280px">

srcset属性の幅記述子のwは省略すると無限大の横幅として扱われる。

画像を解像度で切り替える場合

<img src="基本の画像URL" srcset="通常の解像度の画像URL 1x, 二倍の解像度の画像URL 2x">

srcset属性のピクセル密度記述子のxは省略すると1xとして扱われる。

関連:サイトの画像を高解像度ディスプレイに対応させてパフォーマンスを上げる

三つの属性が画像のレスポンシブ配信に使われる。

src属性
基本の画像URLを入力する。
srcset属性に未対応のブラウザが使用する。
srcset属性
デバイス毎の画像URLを入力する。
画像URLに半角スペース( )を挟んで幅記述子のwかピクセル密度記述子のxを付けた数値、画像の実際の横幅か画面の画面の解像度の倍率を指定して他の画像URLがあれば半角コンマ(,)で区切る。
レスポンシブ配信でブラウザが使用する。
sizes属性(srcset属性が幅記述子の値を持つ場合)
画像の適用条件を入力する。
半角括弧(())で条件項目を示す。max-width(最大幅/そ以下という場合)かmin-width(最小幅/それ以上という場合)に半角コロン(:)を挟んで画面幅(%の単位は不可)を指定する。省略した場合はその他(指定があれば指定以外、指定がなければ全ての場合)の条件項目となる。そして条件内容/スロット幅の画像サイズ(%の単位は不可)を指定して他の条件項目があれば半角コンマ(,)で区切る。何も記載しない場合は100%の画面幅(画面幅の画像が必要)として扱われるようだけど、ただしHTML Living Standardの仕様では幅記述子のsrcset属性と共に欠かせないとされる(img要素のsizes)。
ブラウザがsrcset属性の画像の選択に使う。

imgタグのレスポンシブ配信はマークアップは簡単だけれどもサイトでどうなるかが分かり辛いので、注意を要する。src属性は必要な画像URLの完全な予備だから除外するとしてsrcset属性の挙動やsrcset属性とsizes属性の関係を理解しなくては上手く使えない。

srcset属性の画像のレスポンシブ配信の内容

レスポンシブ配信はsizes属性の条件に照らして最も相応しいsrcset属性の画像が選ばれて表示されるけど、ただしHTMLの仕様で完全に決められたものではなく、ブラウザの裁量によって画像の表示に違いが出て来るので、全て同じになると想定すると混乱するかも知れない。

参考:img の srcset 指定時に選択される画像

画像は画面幅と解像度が加味されて表示される

※高解像度のスマホは横幅320px以上、高解像度のタブレットは横幅640px以上の画像でも表示される。

サンプルのソースコード

<img src="基本の画像URL" srcset="スマホ向け画像URL 320w, タブレット向け画像URL 640w, パソコン向け画像URL 1024w" sizes="(max-width:1280px) 100vw, 1280px">

厄介なのは画面幅だけでレスポンシブ配信が決まらない。だからスマホで大きな画像が使われることがあり、昨今だと高解像度の画面が当たり前だろうからスマホの画面幅にぴったりの320wなどを指定しても使われることは殆どなさそうだ。

高解像度の画面にはそれだけ横幅の大きな画像が使われる。なのでsrcset属性には高解像度用のマークアップのピクセル密度記述子があるけれども画像幅のマークアップの幅記述子で代用することもできる。画面が二倍の解像度ならば指定された画像の二倍の横幅のものが使われるというように前者の倍率と後者の横幅には正比例の関係がある。

サンプルソースコードはおよそスマホとタブレットとパソコンの画像幅に合わせた画像を指定しているけれども僕のスマホやタブレットではパソコン用の大きな画像が表示されている。五年以上前の機種でも解像度は二三倍だからもう本当に小さな画像を指定しても一般的に使われるとは考え難い。

画面幅で画像を確実に振り分ける方法

画像のレスポンシブ配信をデバイスの画面幅だけできっちり行うにはpictureタグのsourceタグにsrcset属性とmedia属性を使うのがどんなブラウザでも反映して最善策だ。

画像サイズを示している

※およそスマホで横幅320px、タブレットで横幅640px、パソコンで横幅1280pxの画像が表示されるだろう。

サンプルのソースコード

<picture>
<source media="(max-width:480px)" srcset="スマホ向け画像URL">
<source media="(max-width:960px) and (min-width:481px)" srcset="タブレット向け画像URL">
<source media="(min-width:961px)" srcset="パソコン向け画像URL">
<img src="基本の画像URL">

pictureタグのsourceタグのsrcset属性とsizes属性の挙動はimgタグの場合と変わらず、一定ではなく、ブラウザによって挙動が異なる。しかしsourceタグにmedia属性を使うと画面幅でsourceタグの使い分けができるからsrcset属性から画像を表示することができる。

画像URLは上から選択されて行くので、基本のsrc属性は振り分けのsrcset属性の後に記載しないと先に表示されてしまってレスポンシブ配信にはならない。

imgタグのsrcset属性はスマホで小さな画像を出して表示速度を確実に上げるのには向いてなくて画質も保って総合的にパフォーマンスを上げるのに役立つ。

srcset属性の幅記述子の省略は画像選択に影響する

AndroidのChromeで画像の出方が変わったからちょっと触れておきたい。

srcset属性の幅記述子の省略は只単にマークアップを楽にする以外に画像選択を変える可能性がある。

※高解像度のスマホやタブレットでも横幅1280pxの画像は表示されないかも知れない。

サンプルのソースコード

<img src="基本の画像URL" srcset="スマホ向け画像URL 320w, タブレット向け画像URL 640w, パソコン向け画像URL" sizes="(max-width:1280px) 100vw, 1280px" sizes="(max-width:1280px) 100vw, 1280px">

AndroidのChromeだと高解像度のスマホやタブレットで640wまでの画像しか選ばれなくなる。

srcset属性のパソコン用の三番目の画像URLに幅記述子の「1024w」を付けると高解像度のスマホやタブレットで表示される。

幅記述子を省略すると無限大として扱われることがブラウザの画像選択に影響を与えるようで、それぞのブラウザで影響の仕方は異なるにせよ、実際にサイトで使われる画像が変わる場合があり得るので、注意しないと画質が下がるかも知れない。

sizes属性のレスポンシブ配信の役割

imgタグのsrcset属性の複数の画像URLはsizes属性の条件に従って選択される。

sizes属性がなければデバイスの画面幅が条件になってぴったりに近いsrcset属性の画像が表示されることになる。

sizes は、一連のメディア条件(例えば画面の幅)であり、特定のメディア条件が成立したときに、どの寸法の画像を選択するのが最適かを示します。

レスポンシブ画像|MDN

srcset属性の画像はsizes属性の画面幅で振り分けられて指定されたサイズに見合ったものがブラウザに選ばれて表示される。

ただし注意しなくては行けないのはsizes属性はsrcset属性に対して示唆的なものでしかないということだ。つまりブラウザがサイトに必要な画像を選択して表示するための決定的な要因にはならない。だからsizes属性の挙動に関してはsrcset属性と同じようにそれぞれのブラウザでばら付きも出て来る。

例えばAndroidのChromeでは非常に小さな画像を指定しても画面の横幅一杯の画像しか選ばれず、sizes属性を完全に無視したような初期値と変わらない挙動になっている。

使っても仕様がないというか、本当に画像選択に影響するとは考えられない。

AndroidのChromeでもう一つ独特なのは画像の表示領域がsizes属性で変わってしまう。非常に小さな画像を指定すると使われる画像は画像の横幅一杯の画像で大き過ぎるのに指定された非常に小さいサイズに狭められて表示されている。

HTMLの仕様ではsizes属性が画像の表示領域に影響するとまでは画定されてないけれどもブラウザによってデザインが変わり得るから注意しなくては行けない。

imgタグのwidth属性やCSSのwidthで変更できるけれども何もしないとsizes属性で画像の表示される横幅が決まってしまう場合がある。

コメント