画像のレスポンシブ対応にimgix(画像配信CDN)を使ってみた

適切な画像を出し分けるため(レスポンシブ画像対応)に何枚も画像を準備するのは大変です
でも
CDNを使えば、高画質な画像1枚準備するだけ、画像のトリミングや最適化ができて読み込みスピードが改善します

「imgix」は1000枚まで無料枠で使えそうです😀

まずはあやふやな、picture要素と srcset・sizes属性を復習してから😅

目次
  1. picture要素とsrcset/sizes属性の復習
    1. imgタグのsrcset属性とsizes属性の使い方
      1. srcset属性
        1. x単位(ピクセル密度)
        2. w単位(画像の横幅)
      2. sizes属性
    2. picture要素
    3. (ついでに)background-image
      1. image-set
      2. resolution
  2. imgix
    1. 無料枠
    2. 設定方法
  3. 「imgix」のパラメーター
    1. srcsetの使用(x)
    2. srcsetとsizesを使用(w)
    3. 最適化
    4. アートディレクション(picture要素)
      1. トリミングする
        1. メインコンテンツが中央にある場合
        2. メインコンテンツが中央にない場合
    5. デフォルトパラメータの設定
  4. 画像削除について
    1. パージリクエスト
  5. 最後に

picture要素とsrcset/sizes属性の復習

そもそも画像を複数準備するシチュエーション

1つ目見た目が同じでサイズが違う画像
高解像ディスプレイへの対応(Retinaなど)やデバイスの幅に応じて最適化する場合(デバイスピクセル比で画像を切り分ける場合)は、imgタグだけ(srcset属性とsizes属性)で切り分けできる

PCで見たときに640pxの画像があった場合、Retinaに対応する場合1280pxの画像が必要
同じ画像をiPhoneで見た場合、iPhoneの横幅は320pxとして640pxで十分

2つ目見た目が異なる画像
デスクトップは横長、スマートフォンは縦長なのが問題(どちらも正方形だったらいいのに 😅 )
アートディレクション(デバイス毎に見た目の異なるトリミングした画像を使う場合)はpicture要素を使う
それぞれの画像ごとにデバイスピクセル比の違いにも対応する

デスクトップで表示した画面

デスクトップで表示

スマフォで表示した画面

同じ見た目の画像をスマートフォンで表示(これだと小さい)

仮に見た目がこれでOKでも、デスクトップ用の大きなサイズとスマートフォン用の小さなサイズの使い分けはimgタグのsrcset属性とsizes属性を使う

トリミングした見た目の違う画像をスマフォ画面に表示

スマートフォン用にトリミングした画像を使う
この場合はpicture要素を使う

imgタグのsrcset属性とsizes属性の使い方

「画像のファイルパス・ピクセル密度または画像の横幅 表示したい画像幅」の情報をブラウザに提供

考え方
適切な画像をブラウザに選んでもらうために「用意している画像の情報」と「表示したい画像幅(可変の時)」を伝える

ブラウザはCSSとJavaScriptの読み込みが完了する前に画像のダウンロードを開始するので、ページのレイアウトを知らずに画像をダウンロードしてる

幅が固定ならsrcset属性だけでOK (用意した画像のピクセル密度)

<img srcset="images/sample.jpg 1x,
             images/sample_2x.jpg 2x"
     src="images/sample.jpg" alt="ピクセル密度">

幅が可変する場合(用意した画像の横幅と表示したい画像幅)

<img srcset="images/sm.jpg 320w, 
             images/ md.jpg 480w,
             images/lg.jpg 800w"
     sizes="(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px"
     src="images/lg.jpg" alt="画像の横幅">

src属性には未対応のブラウザ(IE)が読み込むデフォルトの画像を指定

ちなみにloading=”lazy”で遅延読み込みできる(picture 要素で使う場合もimgタグにつける)
注意点
loading=”lazy”はファーストビューになる画像には指定しない

srcset属性

画像のファイルパス・ピクセル密度または画像の横幅をsrcset属性に記述 (切り出した画像情報リスト

srcset="画像のファイルパス ピクセル密度xまたは画像の横幅w"
x単位(ピクセル密度)

「ピクセル密度」(1x や 2x など)により指定
1000px ある画像を 500px として表示したい場合は、1000 / 500 で「2x 」と記述

sizes 属性不要
メディアクエリが使えない(幅は固定
ブラウザは1xに該当するサイズで画像を表示しようとする

w単位(画像の横幅)

実際のピクセルでのサイズ(単位は w )で指定
実際は 1000px ある画像を 500px として表示したい場合でも1000w と書く

sizes 属性が必要
メディアクエリを使用 (幅は可変
ピクセル密度 = wの値 / sizes で決定されたサイズになる
ブラウザはデバイスピクセル比と比較し画像を選ぶ

sizes属性

srcset属性でw単位を使った時のみ記述
表示したい画像幅をsizes属性に記述(*本質はsrcset属性で指定した画像の中のどの画像を表示するかブラウザが決めるための情報)

単位は em, rem, px, など
% が使えないので割合で指定したい時にはビューポートに対する割合で記述
(ビューポート幅の半分のサイズで画像を表示するなら sizes=”50vw”)

sizes="(max-width: 320px) 280px"

メディアクエリで条件を指定、条件が成立したときにどの寸法の画像を表示するか

sizes="calc(100vw - 300px)"

calc() 関数が使える
例えば、サイドバーの幅300pxを除いた残りの幅

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

1280pxまではビューポートサイズに対して100%で、それ以外は1280pxの固定
条件はカンマで区切る

picture要素

media属性で開発者が表示する画像を選ぶ

picture要素の中に

  • 複数のsourceタグ
  • 1つのimgタグ

sourceタグの属性

  • srcset属性
  • sizes属性
  • media属性(メディアクエリ)
  • type属性(type属性は、MIMEタイプで指定)

対応ブラウザでのみWebP画像を表示する場合は

<picture>
  <source srcset="/hoge.webp" type="image/webp"/>
  <img src="/hoge.png" />
<picture>

media属性にマッチするものがあればsrcset属性で指定された画像を表示
マッチするものがない場合はimgタグの画像が表示される
(順番注意:マッチしたらそれ以降は無視される)
ブラウザがpictureタグに対応していない場合も、imgタグの画像が表示される

<picture>
  <source
   srcset="images/lg.jpg 1x, images/lg.jpg 2x"
   media="(min-width: 1280px)"
  >
  <source
    srcset="images/md.jpg 1x, images/md.jpg 2x"
    media="(min-width: 768px)"
  >
  <source
    srcset="images/sm.jpg 1x, images/sm.jpg 2x"
    media="(min-width: 480px)"
  >
  <img srcset="images/lg.jpg 1x, images/lg.jpg 2x"
       src="images/lg.jpg"
  >
</picture>

(ついでに)background-image

使ったことがない
装飾目的の場合でも、imgタグのalt属性を空にしてimgタグを利用するか 
SVGが使えたらSVGの方がシンプルでいい気がする 😅

image-set

CSSの関数表記(srcsetのx単位と同じような使い方)

.sample {
  background-image: url(icon1x.png);
  background-image: -webkit-image-set(  
    url(icon1x.png) 1x,  
    url(icon2x.png) 2x  
  );  
  background-image: image-set(  
    url(icon1x.png) 1x,  
    url(icon2x.png) 2x  
  );
}

-webkit のベンダー プレフィックス必要
非対応の場合は 1x のアセットを代用

resolution

解像度によるメディアクエリ

@media screen and (min-resolution: 1dppx) {}

1dppxは96dpi でもいい(2dppxは192dpi)
ピクセル (px) あたりのドット数を表します

imgix

無料枠

  • 1,000 Origin Images
  • Infinite Transformations
  • Bandwidth Included 100MB
  • 2 Unique Sources
  • 2 Unique Users

設定方法

Sources(オリジナル画像の保存場所)の選択肢

  • Amazon S3
  • Google Cloud Storage
  • Microsoft Azure
  • Webフォルダー
  • Webプロキシ

わたしの場合は「Webフォルダー」を選択して、契約してるレンタルサーバーの「public_html」直下に「images」フォルダを作りました

その場合

imgix設定画面
  • Source Type:Web Folderを選択
  • Base URL :自分のドメイン/images (imagesにすると画像読み込み時のフォルダ名が省略できる
  • imgix Subdomain :サブドメイン名を自由に決める(サブドメイン名はソースに固有であり、再利用できません)

サービスをテストする場合は、後で本番サイトに必要のない名前を使用することをお勧めします。ドメイン名は、最初のソースに密接にリンクされたままになります
だそうです ^^;

https://サブドメイン名.imgix.net/画像名 

imagesフォルダに画像を置くと、このURLで元画像が呼び出せます

https://サブドメイン名.imgix.net/画像名?w=900&h=300 

パラメーターを追加することで、画像のトリミングや最適化ができます
例えば幅と高さを設定

「imgix」のパラメーター

詳細はこちら

srcsetの使用(x)

固定幅

<img
  srcset="URL?w=400&dpr=1 1x,
   URL?w=400&dpr=2 2x,
   URL?w=400&dpr=3 3x"
  src="URL?w=400"
>

wとdprを使用(dprは5まで)
wは表示幅

dpr使用時の最適化
fit=max(画像が元のサイズより大きく配信されない)
q= 圧縮(デフォルトはq=75)デバイスピクセル比が高いほど数字を低くしてファイルサイズを小さくする

?w=400dpr=1 1x
?w=400fit=max&q=40&dpr=2 2x
?w=400fit=max&q=20&dpr=3 3x

srcsetとsizesを使用(w)

可変幅

<img
  srcset="URL?w=1024&h=1024&fit=crop 1024w,
          URL?w=640&h=640&fit=crop 640w,
         URL?w=480&h=480&fit=crop 480w"
  src="URL?w=640&h=640&fit=crop"
  sizes="(min-width: 36em) 33.3vw, 100vw"
>

36em以上のビューポートでは、画像はビューポート幅の1/3それ以外は100%
wは表示幅(多分💦 )
wのみでサイズを変更する場合は、fit=clipを使用(アスペクト比を保つため)

wの幅を通常のsrcsetのw単位同じように1000pxある画像を500pxとして表示したいとき「1000w」で設定したらスピードに変化はなかった
単純に500wでよささうです

最適化

auto=format
WebP対応ブラウザの場合、WebP形式に変換
auto=compress
ファイルサイズを大幅に節約できますが、画質と色の忠実度が多少損なわれる可能性があり

アートディレクション(picture要素)

トリミング、サイズ(w h)、デバイスピクセル比(dpr)を調整

トリミングする

fit=crop
寸法の変​​更によって引き起こされた無関係なデータを処理する
fit=clip
wは最大サイズ、hはアスペクト比を保つ寸法に調整される
メインコンテンツが中央にある場合
 <source
    srcset="URL?w=568&h=320&fit=crop"
    media="(min-width: 480px)"
  >
メインコンテンツが中央にない場合

この辺りのパラメーターで調整

  • fp-x=0.4 (x座標を左端から開始して全幅の40%に移動します)
  • fp-y=0.35 (y座標を上端から開始して全高の35%に移動します)
  • fit=crop&crop=faces(顔を検出機能を使用して、顔を中心に配置)
  • fit=crop&crop=entropy(コントラストの高い領域を探し、焦点を合わせる)

参考

デバイスピクセル比にも対応

<source
    srcset="URL?w=768&h=768&fit=crop&dpr=1 1x,
            URL?w=768&h=768&fit=crop&dpr=2 2x,
            URL?w=768&h=768&fit=crop&dpr=3 3x,
            URL?w=768&h=768&fit=crop&dpr=4 4x,
            URL?w=768&h=768&fit=crop&dpr=5 5x"
    media="(min-width: 768px)"
  >

デフォルトパラメータの設定

auto=format以外はデフォルトパラメータとして設定できる
個別に上書きできる

「Sources」「View」「Edit」から編集後「Review & Deploy」をクリック

imgixのSources編集画面

画像削除について

画像を変更する場合は、ファイル名の変更が最善の方法

画像の削除は、どうしても必要な場合にのみパージリクエストをする

パージリクエスト

パージは慎重に使用することをお勧めしますとのこと

  • ソースに保存されているマスターイメージへの変更は、システム全体の派生物にすぐに適用されない
  • パージを開始する前にマスター画像の削除を完了する必要がる(マスターに変更がない場合、再検証ステップで停止するためパージは完了しません)
  • パージは、エンドユーザーのブラウザキャッシュに影響を与ない
  • 画像を削除すると、その画像のすべての派生物も削除されます(合成に使用されている画像をパージするときに特別な注意を払う必要がある)

など

パージが必要な状況

  • 同じファイル名を使って画像を変更する必要がある場合
  • imgixを介して提供されている不要な画像や古い画像を完全に削除する必要がある場合

パージ方法

  • ダッシュボードからのパージ
  • カールコマンドでのパージ 

など

最後に

imgix利用前のlighthouseの結果

imgix利用前

imgix利用後のLighthouseの結果

imgix利用後

すごい効果 😊
画像が散らからなくて便利です
パラメーターを書くのが慣れなくて大変でした^^;

imgix.jsなるものがあるので、使えるようになるともう少し横着できるかな😅