※この記事は5年以上前の記事です。
現在は状況が異なる可能性がありますのでご注意ください。
どうも、おひさです。
繁忙期過ぎても忙しくて、全然更新できなかった・・・。
というか、ドメイン死んでモチベーションが下がったw
さて、表記の件だが、
二回に分けて、
特に難しいかつ、重要視される、三つの課題をクリアできる記事にしようと思う。
今回は二つくらいクリアできるかな。
なんでこの書こうかと思ったかというのも、今年の10月あたりから、急にモバイルの基準が厳しくなったのはご存知だと思いますが、
当サイトも、それまで97点とかいってたのに、50点あたりまで下げられてしまい、なんとか、70点以上キープできるようになったのででした。
ほんとねー、余計なことすんなよ、Gよ・・・。
特に、WebPとか使えってったてさ、ほとんどのブラウザで表示できねーじゃねーかよ・・・。
と、愚痴はここまでにして、本題に入ろうか。
厳しくなる前でもあった項目もあるが、
特に難しい対策、敷設は、以下だろうと思う。
- ・レンダリングを妨げるリソースの除外
- ・次世代フォーマットでの画像の配信(効率的な画像フォーマットもほぼ併さる)
- ・オフスクリーン画像の遅延読み込み
今回は、上二つの対策方法をやっていこう。
■レンダリングを妨げるリソースの除外
これに関しては、実は悲しいことに、外部からCSS、JavaScriptを読み込んでいる限り、永遠に警告が消えない。
そんな言っても、インラインにしたら管理ができなくなるじゃん・・・。
ということで、サーバーサイドでインラインに出力しちゃおうというやつである。
実は、一回その記事書いたことあるんだよ。
今回は、それをちょっとだけ使いやすくしたものを公開しようかと。
今回はPHPだが、必要に応じて、PHP以外のサーバーサイド言語に書き換える必要があろう。
下記のPHPスクリプトをどこかに置き、
<?php /* ファイルを読み込み、インライン出力する */ define('SEARVER_SITE_ROOT', 'サーバーのルートパス書いとく'); // ↑は別に、下記で環境変数を使えば別に定義しなくてもいい function cssOutput( $cssRoot = 'common/css/', $cssFileName = 'common' ) { $cssFile = file_get_contents(SEARVER_SITE_ROOT . $cssRoot . $cssFileName . '.css'); if ($cssFile) { $cssFileInner = str_replace("(../images", "(/" . $cssRoot . "images", $cssFile); $cssLast = ''; $cssArray = explode("¥n", $cssFileInner); // とりあえず行に分割 $cssArray = array_map('trim', $cssArray); // 各行にtrim()をかける $cssArray = array_filter($cssArray, 'strlen'); // 文字数が0の行を取り除く $cssArray = array_values($cssArray); // これはキーを連番に振りなおしてるだけ foreach ($cssArray as $key => $value) { $cssLast .= $value; } // 複数行コメントアウトトル $cssLast = preg_replace('/¥/¥*([^¥]|¥*[^¥/])*¥*¥//s', '', $cssLast); return '<style type="text/css">' . $cssLast . '</style>'; } } function jsOutput( $filepath, $idText = null ) { $js_str = file_get_contents( SEARVER_SITE_ROOT . $filepath ); if( $js_str === false ) { return ''; } else { return '<script' . ($idText ? ' id="' . $idText . '"' : '') . '>' . $js_str . '</script>'; } }
んで、このPHPを読み込む。
<?php require_once( '/サーバーのルートパス/common/script/view_includ.php' ); ?>
実際に使うには、下記のようにする。
<?php // CSSを読み込む // 第一引数には、cssファイル格納のディレクトリ、第二引数には、ファイル名を入れる // 上記のようにするのは、画像の相対パスを解決するため echo cssOutput('common/', 'common'); ?> <?php // JavaScriptを読み込む echo jsOutput('common/js/common.js'); ?>
これで、ファイル読み込み自体は、サーバーサイドで行われ、HTML上では、インライン出力となるため、
PageSpeed Insights(以下PSI)では文句を言われなくなる。
■次世代フォーマットでの画像の配信(効率的な画像フォーマットもほぼ併さる)
この課題をクリアするには、
大きく分けて二つの敷設を行う必要がある。
img要素に新フォーマットの画像を当て込むこと、
そして、CSSのbackground-imageに、新フォーマット画像を当て込むことだ。
img要素の置き換えはそんなに難しくない。
例えば、PNGだった画像にWebPを当て込むには下記のようにする。
<picture> <source srcset="hoge.webp" type="image/webp"> <img src="hoge.png"> </picture>
picture要素を使い、後方互換として、imgを入れ、従来の画像フォーマットを当て込めばいい。
こうしておけば、picture要素に対応しているブラウザはもちろん、
IEでも、pictureを無視し、imgを表示してくれるって寸法だ。
画像フォーマットには、WebPが一番適当だろう。
JPEG 2000、JPEG XRなどもあるが、
その中では普及率が高く、画質もそこまで変わらない。
(むしろ、JPEG 2000は若干重いような気がする)
だが、問題は、background-imageなどで指定する画像だ。
PSIのやつは、ここにまでチャチャをいれてくる。
JSで差し替えるのは意味がない。
Webページが読み込まれた時点で、WebPなりを使用していないと、警告がでるからだ。
そこで、先ほどのインライン出力スクリプトが役に立つ。
CSSファイル本体の方では、webpやjp2を使用したうえで、
先ほどのインライン出力スクリプトを下記のように書き換える
<?php /* ファイルを読み込み、インライン出力する */ define('SEARVER_SITE_ROOT', 'サーバーのルートパス書いとく'); define('INNER_UA', mb_strtolower($_SERVER['HTTP_USER_AGENT'])); define('IPHONE_FLG', (strpos(INNER_UA, 'iphone') !== false || strpos(INNER_UA, 'ipod') !== false)); define('ANDROID_FLG', (strpos(INNER_UA, 'android') !== false && strpos(INNER_UA, 'mobile') !== false)); define('WEBP_FLG', ( (strpos(INNER_UA, 'chrome') !== false && strpos(INNER_UA, 'edge') === false) || strpos(INNER_UA, 'opera') !== false )); function cssOutput( $cssRoot = 'common/css/', $cssFileName = 'common' ) { $cssFile = file_get_contents(SEARVER_SITE_ROOT . $cssRoot . $cssFileName . '.css'); if ($cssFile) { // iPhoneの場合、いずれの場合もWebPは表示できないので差し替え if (IPHONE_FLG) { // 元がJPEGと示すため、URLパラメータを使用 $cssFile = str_replace(".webp?jpg", ".jpg", $cssFile); $cssFile = str_replace(".webp", ".png", $cssFile); } // Androidは、jp2に対応していないので差し替え if (ANDROID_FLG) { $cssFile = str_replace(".jp2", ".jpg", $cssFile); } // PCでは、Google Chrome、Opera以外はWebPに対応してないため、差し替え if (!WEBP_FLG && (!IPHONE_FLG && !ANDROID_FLG)) { // 元がJPEGと示すため、URLパラメータを使用 $cssFile = str_replace(".webp?jpg", ".jpg", $cssFile); $cssFile = str_replace(".webp", ".png", $cssFile); } $cssFileInner = str_replace("(../images", "(/" . $cssRoot . "images", $cssFile); $cssLast = ''; $cssArray = explode("¥n", $cssFileInner); // とりあえず行に分割 $cssArray = array_map('trim', $cssArray); // 各行にtrim()をかける $cssArray = array_filter($cssArray, 'strlen'); // 文字数が0の行を取り除く $cssArray = array_values($cssArray); // これはキーを連番に振りなおしてるだけ foreach ($cssArray as $key => $value) { $cssLast .= $value; } // 複数行コメントアウトトル $cssLast = preg_replace('/¥/¥*([^¥]|¥*[^¥/])*¥*¥//s', '', $cssLast); return '<style type="text/css">' . $cssLast . '</style>'; } } // JavaScript出力メソッドは省略
CSSの出力をするスクリプトに、PHPでのブラウザ判定を行い、
それによって、WebPなどに対応していないブラウザでは、
拡張子を、従来の画像拡張子に差し替えているというわけだ。
これなら、PSIで点数を稼ぎつつ、全ブラウザで表示できるってわけ。
CSSと画像の運用も変えずに済む。
本当にね、今回のPSIのアップデートでイラっときたのは、
新しいフォーマット使えってことなんだよ。
そんなクッソ普及してない過疎フォーマット使えって、無理があるって。あほかって。
もっと、寛大な点数の付け方をしてもらいたいものだ・・・。
さて、次の記事では、これまた難しい、
オフスクリーン画像の遅延読み込みについてやっていく。
ではまた。
コメントする