2021.08.27

コーディング

【picture要素検証】WebP/Retina/SP/PC それぞれの画像を出し分ける ~picture要素はIEでも使えます~

 tanuki

👆 閲覧環境判定タヌキ

ユーザーの使用しているデバイスやブラウザによって表示させる画像を出し分けたいとき――例えばSP・PCで画像を変えたいなんてとき、よく見かける方法としてimg要素を二つ用意してクラスをつけてcssで表示非表示を切り替える方法があります。
この方法は結構メジャーで、こうして画像を切り替えているサイトもたくさんあるでしょう。

ですが!

ブラウザのdeveploperツールを見てみると、この方法では非表示に指定している画像まで読み込んでしまっているのが確認できます。

この最低限のHTMLとSCSSが書かれたコードペンの画面で見てみましょう👇
※ PCで見てるのにSPの画像がでてる人は、コードペンのタイトルをクリックしてページに飛べばPCの画像が表示されると思います。

See the Pen by nokurakazuha (@nokura) on CodePen.

見方をchromeの場合で説明します。他のブラウザでもだいたい似たような感じです。

上記のコードペンを開いた後、F12キーを押下、もしくは適当な場所で右クリックメニューから「検証」を選択するとdeveploperツールが開きます。

deveploperツールの「Networkタブ」を開くと読み込めれたファイル一覧が見れますが、表示される画像は一つなのに

  • pictureelement_pc.jpg
  • pictureelement_sp.jpg

二つの画像が読み込まれてしまっているのが分かります👇(※ クリックで大きい画像が別タブで開きます)

サイトの表示スピードというのはとても大事なので、非表示の画像まで読み込んでいるのは非常に痛手です。画像はテキスト等に比べてものすごく重いですからなるべく無駄な読み込みはさせたくありません。

そんなときに使えるのがpicture要素

picture要素はHTML5.1で追加された要素で、レスポンシブイメージを実現するためのものです。

今回実際にpicture要素を使って様々な条件で画像を出し分けてみましたが、picture要素はきちんと表示したい画像のみを読み込んでいることが確認できました。
※ 最後の「まとめ」で実際に出し分けているコードをコードペンで確認できます。

しかし、そんな優秀なpicture要素をcan I useで検索してみると……

やっぱりIEでは非対応……

このことでpicture要素を使用することを今まで躊躇していたのですが、実際に使って色々と検証した結果、「問題ない」という結論に至りました。

「問題ない」というよりも、picture要素の便利さを実感した検証結果になりましたので今回はpicture要素についての軽い説明と検証内容についてお話します。

picture要素はIEでも使える!

使える! とまで書いたら語弊があるかもしれません。
実際には「IEでも問題ない」という感じです。

冒頭で書いたようにcan I useではIE非対応となっているpicture要素ですが、MDNのドキュメントでは以下のように書かれています。

ブラウザーが 要素に対応してない場合、 要素の src 属性で指定された URL が選択されます。

IEでもsrc属性で指定された画像はちゃんと表示されるのです。
ですので、「IEでは画像が表示されないのではないか?」とか「エラーが発生してしまうのではないか?」といった心配は不要ということです。

ただし、出し分けはできません。

この「デバイスやブラウザによって出し分ける」という部分が非対応という訳っぽいですね。

ですが、IEで画像の出し分けって必要でしょうか?

後述しますが、picture要素によって以下のような出し分けができます。

  • デバイス幅 【SPかPCか】 による出し分け
  • ブラウザの対応画像形式 【webPに対応しているか】 による出し分け
  • ディスプレイ 【高画素密度ディスプレイ(レティーナディスプレイ等)かどうか】 による出し分け

①について
IEを利用しているということはデバイスはPCだと思われるので、「PCかSPか」による画像の出し分けは考えなくてよいでしょう。(スマホのIEも存在するようなのですが、流石に考慮しなくてよいかと…)
PCでIEを利用していて、かつ、ブラウザ幅をめちゃくちゃ細くして見ている人は拾えないですが、そんなもの拾ってはいけません。もといた場所に捨ててきなさい。

②について
webPにはもちろん対応してないのでこちらも考慮要らず、

③について
IEユーザーということはwindows機ユーザーでしょうからレティーナディスプレイかどうかもそこまで気にしなくていいと思います。
高DPIのとても良いディスプレイを使用しているIEユーザーもいるかもしれないですが、高DPIディスプレイによる出し分けは主に「2倍サイズ画像を送るかどうか?(2倍以外もあります)」ということだと思いますので、IEユーザーにも綺麗な画像を見せたい! というのであればsrc属性に指定する画像を2倍サイズに、IEユーザーなんてちょっとくらい画像ボケてても気にせんやろ! というのであれば等倍の画像を指定しておけばよいと思います。

ただこれはIEに限った話ではないですが、冒頭でも触れた通りサイトの表示速度において最も如実に影響が出るものの一つが画像容量です。
2倍サイズの画像ということは(圧縮方法にもよりますが)単純に考えればピクセル情報が縦2倍、横2倍すなわち2×2=4倍になってしまうのでよほど綺麗に見せたい画像でなければ等倍を選んでおくのが無難だと思います。

以上のことから、picture要素を使用してもsrc属性にPC用の画像をきちんとセットしておけばIEでも問題ないと個人的には思います。

picture要素の構成

picture要素は以下のように複数の
<source>
と一つの
<img>
を持ちます。
<source>
はいくつでもかまいません。
<picture>
  <source ・・・>
  <source ・・・>
  <source ・・・>
 <img src="○○.jpg" alt="説明">
</picture>
<source>
には様々な条件と、その条件に合致した場合に表示させたい画像URLを、
<img>
にはどの条件にも合致しなかった場合や、picture要素非対応のブラウザに提供したい画像URLを指定します。(画像の寸法を指定する役目もあります)

【目的別】出し分け条件

実際にどんな条件を
<source>
に書けばよいか、目的別に書いていきます。

SPとPCで出し分けたい【media属性】

一番頻度が高いのがスマホとパソコンでの出し分けだと思います。 場合によってはタブレットでも出し分けたいときがあるかもしれませんがやり方は同じです。

画面サイズ条件で画像を出し分けるのですが、cssで使うメディアクエリ(
@media
)と同じように
<source>
media属性を持っています。
<picture>
 <source media="(min-width: 1200px)" srcset="PC.jpg">
 <source media="(min-width: 900px)" srcset="TABLET.jpg">
 <source srcset="SP.jpg">
 <img src="PC.jpg" alt="説明">
</picture>

上記の例でいくと、「min-width: 〇〇px」は、「少なくとも〇〇px」、すなわち「〇〇px以上」ということになりますので、上から順に

  • 1200px以上ならPC.jpg
  • 900px~1199pxならTABLET.jpg
  • 899px以下ならSP.jpg

の3パターンで出し分けてくれます。

<source>
は上から順に評価され、条件がfalseと評価されれば次の要素が評価されます。
if → elseif → ・・・ → elseif → else みたいな感じです。
数値もパターン数も都合の良いように指定できます。

「min-width」があれば当然「max-width」もあります。
「max-width: 〇〇px」は、「高々〇〇px」、すなわち「〇〇px以下」ということになりますので、

<picture>
 <source media="(max-width: 900px)" srcset="SP.jpg">
 <source media="(max-width: 1200px)" srcset="TABLET.jpg">
 <source srcset="PC.jpg">
 <img src="PC.jpg" alt="説明">
</picture>

上記のように書けば、

  • 900px以下ならSP.jpg
  • 901px~1200pxならTABLET.jpg
  • 1201px以上ならPC.jpg

の順番で出し分けることができます。

SPとPCでの出し分けを実際にやっているコードペン👇

See the Pen by 葉っぱ一号 (@nokura) on CodePen.

PC時、SP時、それぞれに応じた画像のみが読み込まれているのが分かります。

webp対応のブラウザにはwebp画像を表示させたい【type属性】

新しい画像形式であるwebpは圧縮率も綺麗さも従来の画像形式より優れており是非使いたいものですが、IEはもちろん対応していません。
非対応なのがIEだけならIEを捨てるという手もあるかもしれませんが、なんとPC版safariも対応していないのです。macデフォルトのくせに。スマホ版safariは対応してるのに。(※ 2021年8月現在)

ということで、ブラウザがwebpに対応していたら「〇〇.webp」を、非対応なら「〇〇.jpg(〇〇.png)」といった出し分けをするためにtype属性を使います。

SP・PCの出し分けは、クラス付与での出し分けや、cssの@mediaでの出し分けや、phpでの出し分け等でもできますが、webp対応かどうかの出し分けが簡単にできるのがpicture要素の良さではないでしょうか。

<picture>
  <source type="image/webp" srcset="○○.webp">
  <source srcset="○○.jpg">
 <img src="○○.jpg" alt="説明">
</picture>

このように「type=」の部分にMIMEタイプを指定することで指定の形式に対応したブラウザのみに専用の画像を提供できます。

「image/webp」以外にも「image/apng」や「image/avif」等を指定することでそれぞれの形式の画像が出し分けできるので、新しい形式の画像を試してみたい場合に「表示されない…」なんて自体を回避できるのは非常に助かりますね。

実際のコードペン👇
webpかjpegが表示されます。IEはコードペン自体が非対応なのでjpgが表示されている人はPC版safariの人ですかね?

See the Pen by 葉っぱ一号 (@nokura) on CodePen.

レティーナディスプレイでは2倍サイズの画像を表示させたい【srcset属性】

今回の検証で個人的に一番感動したのがこのレティーナディスプレイ(高画素密度ディスプレイ)での出し分けです。

2倍サイズの画像というのは非常に重くなってしまいますから、一般的なディスプレイを使用しているユーザーにまで重い画像を送り付けてしまうのはサイトの離脱率にも関わる重大な問題です。高画素密度のディスプレイを使用しているユーザーは少数派ですしね。

srcset属性ならこの問題を簡単に解決できるのです!(複数サイズの画像を用意する手間はありますが…)

しかも!

マルチディスプレイの場合にもそれぞれのディスプレイに合わせて画像の出し分けが行われていました!

macbookでの検証時、2倍サイズの画像ではなく等倍サイズの画像が読み込まれており一瞬戸惑ったのですが、そのときブラウザを開いていたのが外部ディスプレイだったので、macbook本体のディスプレイにブラウザを移動した後ページを更新したところ、ちゃんと2倍サイズの画像が読み込まれました。
つまり、macbook本体のディスプレイでサイトを開いた場合は2倍サイズの画像、macbookにつなげた普通の外部ディスプレイでサイトを開いた場合は等倍画像がきちんと読み込まれていたのです!

実際に見て感心してしまったこの画素密度による出し分けは、secset属性に指定する画像をカンマ区切りで複数指定することで実現します。2倍サイズの画像なら後ろに「2x」、3倍サイズの画像なら後ろに「3x」のように「〇x」を付け加えることで適切な画像を選んでくれます。

<picture>
 <source srcset="○○.jpg, ○○_x2.jpg 2x">
 <img src="○○.jpg" alt="説明">
</picture>

たったこれだけの記述で外部ディスプレイまでも判断して出し分けてくれるのは便利な世の中になったものですね。

ちなみに、この画素密度に応じた出し分けのみを使用したい場合はpicture要素を使わずに
<img>
内に
srcset
を加えるだけでもOKです。
ただし
srcset
だけだとIEで表示されないのでIEケアするなら
src
もちゃんと残しておきましょう👇
<img srcset="○○_x2.jpg 2x" src="○○.jpg" alt="説明">

実際に出し分けているコードペン👇
あなたの見ているディスプレイが高画素密度のものなら2倍といっているタヌキが見えるはずです。

See the Pen by 葉っぱ一号 (@nokura) on CodePen.

まとめ

目的別に画像の出し分け条件の書き方について説明してきましたが、これまでのことをまとめると

  • デバイス幅 【SPかPCか】 による出し分け
    ➡ media属性にメディアクエリを記述
  • ブラウザの対応画像形式 【webPに対応しているか】 による出し分け
    ➡ type属性にMIMEタイプを記述
  • ディスプレイ 【高画素密度ディスプレイ(レティーナディスプレイ等)かどうか】 による出し分け
    ➡ srcset属性にカンマ区切りで画像を指定し、〇倍サイズの画像には後ろに「〇x」を追加

となります。

実際にはこれら3つの条件を複合して指定することになると思いますので全ての条件を含めた例を見てみましょう。
複雑に見えるかもしれませんが、一つひとつが分かっていれば難しくないと思います。

<picture>
 <source media="(max-width: 767px)" type="image/webp" srcset="SP.webp, SP_x2.webp 2x">
 <source media="(max-width: 767px)" type="image/jpg" srcset="SP.jpg, SP_x2.jpg 2x">
 <source media="(min-width: 768px)" type="image/webp" srcset="PC.webp, PC_x2.webp 2x">
 <source media="(min-width: 768px)" type="image/jpg" srcset="PC.jpg, PC_x2.jpg 2x>
 <img src="PC.jpg" alt="説明">
</picture>

分け方のイメージはこんな感じです↓

この例では、上の2つの
<source>
がSPなので、下の2つは自動的にSP以外(=PC)になり、実際には下2つにはmedia属性を書く必要はありません。
同様に1つ目と3つ目の
<source>
がwebp指定なので、2つ目と4つ目は自動的にwebp以外(=jpg,png等)になり、2つ目と4つ目にはtype属性を書く必要がありません。

ですので、省略したバージョンはこんな感じです。

<picture>
 <source media="(max-width: 767px)" type="image/webp" srcset="SP.webp, SP_x2.webp 2x">
 <source media="(max-width: 767px)" srcset="SP.jpg, SP_x2.jpg 2x">
 <source type="image/webp" srcset="PC.webp, PC_x2.webp 2x">
 <source srcset="PC.jpg, PC_x2.jpg 2x>
 <img src="PC.jpg" alt="説明">
</picture>
タブレットでも分けたい場合は間に
<source>
が2つ増える感じですね。

総まとめのコードペン👇
あなたのみている環境によって

  • SP・webp・2倍
  • SP・webp・等倍
  • SP・jpg・2倍
  • SP・jpg・等倍
  • PC・webp・2倍
  • PC・webp・等倍
  • PC・jpg・2倍
  • PC・jpg・等倍

の8パターンで出し分けされます。
この記事の冒頭で唐突に表示されていた画像の正体はこれです。 さぁ、あなたの画像はどれだったでしょう。

See the Pen by 葉っぱ一号 (@nokura) on CodePen.

以上でpicture要素の説明は終わりになりますが、今回触れられていない部分もありますので詳しく知りたい方はMDNのドキュメントなんかを読んでみてください。

今回検証してみて実感したpicture要素の魅力は

  • 条件に合った画像のみが読み込まれるので無駄な読み込みがない【ページスピードの向上】
  • ブラウザの対応状況に応じた画像形式を表示させることができる【新しい画像形式でも安心】
  • 画素密度に応じた画像の出し分けができる(特にmacユーザーに対して)【ページスピードの向上】

この3つです。

どれもクラス付けやcssだけではできないことだと思うので、これらを一遍に実現できるpicture要素はとても優秀ですね。

最後に、今回検証したブラウザと実際に表示された画像の一覧です。

ブラウザ 表示された画像
mac chrome webp 2倍
mac chrome(外部ディスプレイ) webp 等倍
mac firefox webp 2倍
mac firefox(外部ディスプレイ) webp 等倍
mac safari jpg 2倍
mac safari(外部ディスプレイ) jpg 等倍
windows chrome webp 等倍
windows firefox webp 等倍
windows IE11 jpg 等倍
iphone chrome webp 2倍
iphone safari webp 2倍



ご覧いただきありがとうございました。

この記事を書いた人

葉っぱ一号

葉っぱ一号

フロントエンドエンジニア

おいしいお店を探すのが好きです。おいしいお店のために遠出もしちゃいます。遠出したい衝動のためにおいしいお店を探すのかもしれません。そんなものですよね。