レ点腫瘍学ノート

pukiwikiカスタマイズ箇所/2020/WEBP画像のフォールバック の履歴ソース(No.14)

#author("2021-11-29T07:52:40+09:00;2020-07-22T07:43:13+09:00","default:tgoto","tgoto")
&tag(pukiwiki);#author("2021-06-19T08:29:06+09:00;2020-07-22T07:43:13+09:00","default:tgoto","tgoto")
#ref(https://oncologynote.com/img/5b041d2a93.png,nolink,WEBP画像のフォールバック)

JPGやPNGなどの画像をWEBP形式にすることによってファイル容量を減らすことができ、ひいては通信速度の向上によりPagespeed insightsのスコアの改善を期待することができます。%%しかしWEBP画像は現時点ではSafariに対応しておらず%% iPhoneやiPadやMacのSafariも2020年秋のアップデートからWEBPに対応しました。

しかし、IEでは開くことができません。このためWEBP画像を使用する場合は非対応ブラウザでは適切なfallbackを設定しておいて従来のJPGやPNGを表示できるようにしてあげなければなりません。

今回はrefプラグインで画像を保存しているフォルダに同名のWEBP画像があるかどうかを探してみて、もしWEBP画像あってかつ対応ブラウザであればWEBP画像を表示し、WEBP画像が存在しないか非対応ブラウザの場合にはもとどおりのJPG画像かPNG画像を表示するという改造を行いました。

*WEBP画像のフォールバックとは [#pbf01c26]

#ogp(https://amp.dev/ja/documentation/guides-and-tutorials/develop/style_and_layout/placeholders/)

高速化のためにWEBP画像を表示できるようにamp-imgを設定しつつ、もしWEBP画像が存在しなかったり非対応ブラウザの場合はJPGやPNGなどの互換性の高いファイル形式を表示できるようにしておくことです。

**AMP対応済みページの場合 [#icc99bf7]

すでに AMP化されているページのamp-imgの場合は設定は簡単で、AMPにはデフォルトで画像のfallbackの機能が備わっているのでamp-imgタグの中にamp-imgタグを入れてfallbackと記載しておくだけです。

><amp-img alt="Mountains"
>  width="550"
>  height="368"
>  layout="responsive"
>  src="/img/image.webp">
>  <amp-img alt="Mountains" fallback
>    width="550"
>    height="368"
>    layout="responsive"
>    src="/img/image.jpg"></amp-img>
></amp-img>

**非AMP対応なページの場合 [#ab778d46]

世の中のwebサイトの大部分はAMP対応していないので、非AMPページの方法も記載しておきます。AMPページではなく通常のHTMLページでもAMPライブラリを読み込んでいれば上記のAMPページ用の方法を使うことは可能といえば可能ですが、非AMPページではpictureタグを使うのが一般的かと思います。pictureタグはIEなどは非対応なので考慮する必要があります。

><picture>
>    <source srcset="image.webp" type="image/webp">
>    <source srcset="image.jpg" type="image/jpeg">
>    <img src="image.jpg">
></picture>

また、上記の真ん中の行は削除しても画像表示可能です。

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

さらに、lazysizesで画像を遅延読み込みしている場合は下記のようになります。

><picture>
>    <source data-srcset="image.webp" type="image/webp">
>    <img class="lazyload" src="dammy.jpg" data-src="image.jpg">
></picture>

#ogp(https://qiita.com/mikimhk/items/abb525c304cf49f30350)

このままではCLSが生じるという問題があり、SEO上好ましくないため、次のリンクにあるような対応も実施しておくことをお勧めします。

#ogpi(https://oncologynote.com/?16f4ac0c0a)

*IEのpictureタグ未対応問題 [#s95dbbfe]

IEではpictureタグが正しく解釈できないという問題がありますが、picturefillというjavascriptを読み込ませることでIEなどでもpictureタグを解釈できるようになります。ChromeやFirefoxを含む最近のモダンブラウザはpictureタグの解釈はできますので、ブラウザを限定してjsファイルを読み込みます。なお、jsdelivrで見つかりにくいところにあるのですが下記のリンクは普通に機能しているようです(2020年7月現在)。これを<head>の下の方に配置しておきます。

><!--[if lt IE 11]>
><script src="https://cdn.jsdelivr.net/picturefill/2.3.1/picturefill.min.js"></script>
><![endif]-->

#ogp(https://techmemo.biz/javascript/picturefill-js/)

*具体的なref.inc.phpの改造内容 [#k540db9d]

pukiwikiを利用している当サイトは画像はスキンやプラグインに組み込まれているか、またはrefプラグインで表示しているものが大部分です。

**当サイトの環境 [#vd8b7ce5]

参考までに、当サイトでは基本的に画像を/img/フォルダに保存しています。また、AMP対応のためにもともとrefプラグインはAMP対応改造を実施していました。

WEBP画像は、画像が保存されている/img/フォルダとOGPプラグインのキャッシュが保存されている/cache/ogp/プラグインの中身をFTPでごっそり持ってきてWebPconvで一気に変換しました。WebPconvはほとんど初期設定のままですが圧縮のeffortだけ6に上げています(デフォルトは4)。%%Windows版しかありませんが%%多数のファイルを一気にWEBP変換するにはオススメです(2021年1月追加:Mac版ものWEBP converterもリリースされ、App storeで入手できます)。 Photoshop CCを持っている場合はバッチ処理で変換してもいいかもしれません。

#ogp(https://apps.apple.com/jp/app/webp-converter/id1522368690?mt=12)

**設定項目PLUGIN_REF_WEBP_FALLBACKの新設 [#r522431d]

まず「フォルダにWEBP画像を探してみてファイルがなければfallbackするか」を設定する項目を作っておきます。40〜41行目に下記の項目を新設しました。フォルダにWEBP画像を探してみるならTRUE、この改造を使用しないならFALSEです。

>// フォルダにWEBP画像を探してみてファイルがなければfallbackするか
>define('PLUGIN_REF_WEBP_FALLBACK', TRUE); // FALSE, TRUE

** 358-363行目 [#sdfcdd55]

358行目付近の具体的な画像のHTMLタグ出力部を下記のように改造します。ちなみに、layoutはintrinsicでもresponsiveでも問題ないはずなのですが、なぜかintrinsicにしているとfallbackされた画像が表示されず真っ白になることがしばしばあり(リロードすると普通に読み込まれる)、responsiveのほうが安定しているような印象です。

***AMP化改造を済ませた時点のrefプラグイン(改造途中) [#d3104631]

PLUGIN_REF_URL_GET_IMAGE_SIZEをTRUEにしておく必要があります。

>	if ($is_image) { // 画像
>		$params['_body'] = "<amp-img src=\"$url\" layout=\"responsive\" alt=\"$title\" title=\"$title\" $info></amp-img>";
>		if (! $params['nolink'] && $url2)
>			$params['_body'] = "<a href=\"$url2\" title=\"$title\">{$params['_body']}</a>";
>	} else {
>		$icon = $params['noicon'] ? '' : FILE_ICON;
>		$params['_body'] = "<a href=\"$url\" title=\"$info\">$icon$title</a>";
>	}

***FALLBACKの設定後のrefプラグイン(改造後) [#ic5d33d0]

>if ($is_image) { // 画像
>if ( PLUGIN_REF_WEBP_FALLBACK ) {
>$urlwebp = pathinfo($url, PATHINFO_DIRNAME ) . '/' . pathinfo($url, PATHINFO_FILENAME ) . '.webp'; //同じディレクトリにwebp画像があるか探す
>}
>if ( PLUGIN_REF_WEBP_FALLBACK && file_get_contents($urlwebp)) {
>$params['_body'] = "<amp-img src=\"$urlwebp\" layout=\"responsive\" alt=\"$title\" $info><amp-img fallback src=\"$url\" layout=\"responsive\" alt=\"$title\" $info></amp-img></amp-img>"; //webp画像fallback
>} else {
>$params['_body'] = "<amp-img src=\"$url\" layout=\"responsive\" alt=\"$title\" $info></amp-img>";
>}
>if (! $params['nolink'] && $url2)
>$params['_body'] = "<a href=\"$url2\" title=\"$title\">{$params['_body']}</a>";
>} else {
>$icon = $params['noicon'] ? '' : FILE_ICON;
>$params['_body'] = "<a href=\"$url\" title=\"$info\">$icon$title</a>";
>}

***AMP化していない場合のFALLBACKの設定後のrefプラグイン(改造後) [#ocbdbdec]

lazysizesスクリプトとpictureタグを使っています。pictureタグはAMPに非対応です。
またIEでpictureタグを正しく表記するためには、後述するjavascriptの読み込みが必要です。

>if ($is_image) { // 画像
>if ( PLUGIN_REF_WEBP_FALLBACK ) {
>$urlwebp = pathinfo($url, PATHINFO_DIRNAME ) . '/' . pathinfo($url, PATHINFO_FILENAME ) . '.webp'; //同じディレクトリにwebp画像があるか探す
>}
>if ( PLUGIN_REF_WEBP_FALLBACK && file_get_contents($urlwebp)) {
>$params['_body'] = "<picture><source type=\"image/webp\" data-srcset=\"$urlwebp\" $info/><img class=\"lazyload\" src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"$url\" alt=\"$title\" $info/></picture>"; //webp画像fallback
>} else {
>$params['_body'] = "<img class=\"lazyload\" src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"$url\" alt=\"$title\" $info/>";
>}
>if (! $params['nolink'] && $url2) {
>$params['_body'] = "<a href=\"$url2\" title=\"$title\">{$params['_body']}</a>";
>}
>} else {
>$icon = $params['noicon'] ? '' : FILE_ICON;
>$params['_body'] = "<a href=\"$url\" title=\"$info\">$icon$title</a>";
>}

なお、ほかに画像を出力するOGPプラグインなどもこの改造を実施しています。

#ogpi(https://oncologynote.com/?12173bf026)

追記:このフォールバックを設定してから、Googleのpagespeed insightsで''First Contentful Paint''が少し向上してページによってようやく1.0sを切ることができるようになり、また''効率的な画像フォーマット''と''次世代フォーマットでの画像の配信''の判定が合格になりました。一方で''最大コンテンツの描画''の時間がごくわずかに(0.2sくらい?)遅くなってしまいました。これがフォールバックのせいなのかどうかは現在調査中です。

#ogpi(https://oncologynote.com/?16f4ac0c0a)

**追記 [#d1c9e90a]

2020.9.17未明にリリースされたiOS 14で、iPhone/iPadおよびMacのSafariもようやくwebpに対応しました。これでwebpはIE11を除くほとんどのブラウザに対応していることになり、JPEG 2000やJPEG XRを抜き去ってWebでの画像フォーマットの標準の地位を確固たるものにしました。

#ogp(https://dsinside.digitalstage.jp/entry/2020/08/19/100744)
#ogp(https://amzn.to/3rvWRcG)