【SEO】PSI対策No.1 - リソースインライン化・WebP導入

謎のプリン語る。
プログラミングの役立つ情報とか、どうでもいい雑談とか書いてます。
一人書く人増えました。

【SEO】PSI対策No.1 - リソースインライン化・WebP導入

みやびプリン 500 316

500 320

【SEO】PSI対策No.1 - リソースインライン化・WebP導入 - サムネイル

※この記事は5年以上前の記事です。
現在は状況が異なる可能性がありますのでご注意ください。

どうも、おひさです。
繁忙期過ぎても忙しくて、全然更新できなかった・・・。
というか、ドメイン死んでモチベーションが下がったw

さて、表記の件だが、
二回に分けて、
特に難しいかつ、重要視される、三つの課題をクリアできる記事にしようと思う。
今回は二つくらいクリアできるかな。

なんでこの書こうかと思ったかというのも、今年の10月あたりから、急にモバイルの基準が厳しくなったのはご存知だと思いますが、
当サイトも、それまで97点とかいってたのに、50点あたりまで下げられてしまい、なんとか、70点以上キープできるようになったのででした。
ほんとねー、余計なことすんなよ、Gよ・・・。
特に、WebPとか使えってったてさ、ほとんどのブラウザで表示できねーじゃねーかよ・・・。

と、愚痴はここまでにして、本題に入ろうか。
厳しくなる前でもあった項目もあるが、
特に難しい対策、敷設は、以下だろうと思う。

  • ・レンダリングを妨げるリソースの除外
  • ・次世代フォーマットでの画像の配信(効率的な画像フォーマットもほぼ併さる)
  • ・オフスクリーン画像の遅延読み込み

今回は、上二つの対策方法をやっていこう。

■レンダリングを妨げるリソースの除外

これに関しては、実は悲しいことに、外部からCSS、JavaScriptを読み込んでいる限り、永遠に警告が消えない。
そんな言っても、インラインにしたら管理ができなくなるじゃん・・・。
ということで、サーバーサイドでインラインに出力しちゃおうというやつである。
実は、一回その記事書いたことあるんだよ。

CSS レンダリング ブロック対策(PHP使用)をする

今回は、それをちょっとだけ使いやすくしたものを公開しようかと。
今回は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のアップデートでイラっときたのは、
新しいフォーマット使えってことなんだよ。
そんなクッソ普及してない過疎フォーマット使えって、無理があるって。あほかって。
もっと、寛大な点数の付け方をしてもらいたいものだ・・・。

さて、次の記事では、これまた難しい、
オフスクリーン画像の遅延読み込みについてやっていく。
ではまた。

ラグナロクオンライン - メイン

トラックバック(0)

トラックバックURL:

コメントする

ページトップへ戻る