【CSS編】ページスピードインサイトで「レンダリングを妨げるリソースの除外」の問題を解決する方法

2019-07-10ページスピードインサイト

PageSpeed Insightsで「改善できる項目」として、レンダリングを妨げるリソースの除外という項目が表示された時の対処方法です。

今回は【CSS編】になります。

レンダリングをブロックするリソースNG

PageSpeed Insights

ページの初回ペイントをリソースが阻害しています。クリティカルな JS や CSS はインラインで配信し、それ以外の JS やスタイルはすべて遅らせることをご検討ください。詳細

もう少し解りやすくすると・・

最初に表示される範囲に使用される必須の CSS と JS は直接書いて、画面外(スクロールして表示される箇所)に関わる CSS と JS は遅らせて読み込ませてあげましょう。

という意味合いです。

まずは、概要から説明していきます。

スポンサーリンク

レンダリングを妨げるリソースとは

主に下記の2つになります。

JS(JavaScript)

ジャバスクリプト(プログラミング言語)の略。

ウェブサイトの中では、主に動きを付ける役割を果たします。

例)

  • 複数画像のスライドショー機能
  • ページ上部に滑らかに戻る機能
  • マップ・カレンダー・コメントフォーム

など・・色々な部分で使われています。

CSS(Cascading Style Sheets)

カスケーディング・スタイル・シート(プログラミング言語)の略。

ウェブサイトの中では、主にデザインを表現する役割です。

例)

  • 文字の色・大きさ・太さ・フォントの指定
  • 背景色・背景画像の指定
  • 画像の装飾・大きさの指定

など、デザインを指定するのに使われています。

これらのファイルは、通常下記のような形式で組み込まれています。

例)

<!DOCTYPE html>
<html lang="ja">
/* ~~~~省略~~~~ */
<head>
<link rel="stylesheet" type="text/css" href="/css/common.css"/> /* 共通デザイン */
<link rel="stylesheet" type="text/css" href="/css/home.css"/> /* TOPページ用デザイン */
<script type="text/javascript" src="/js/jquery-3.3.1.min.js"></script> /* 必須スクリプト */
<script type="text/javascript" src="/js/scroll.js"></script> /* なめらかスクロール */
</head>
<body>
/* ~~~~省略~~~~ */
</body>
</html>

5・6行目が CSSファイルの読み込み。

7・8行目が JavaScriptファイルの読み込みです。

上記はサンプルです。ウェブサイトの種類や規模によって異なります。

レンダリングのイメージ

上から順番にレンダリング(翻訳・描画)していきます。

レンダリングイメージ

実際は下記の通り、各リンク先をダウンロードしながら ①→②→③→④→⑤の順番に読まれていきます。

レンダリングの順番

①で common.css へ読み込みリクエストが発生。ダウンロードし読み込み終えないと②に進めない。(待ち時間が発生)

同様に④までを全て読み込み終えないと、⑤に辿り着けない。

本題:レンダリングを妨げるリソースの除外方法

クリティカルなCSSの特定

クリティカルなCSSとは

スクロールせずに最初に表示される範囲に使用される必須の CSS の事です。

オンライン上で手軽に抽出できるツールがあります。

Critical Path CSS Generator

https://jonassebastianohlsson.com/criticalpathcssgenerator/

クリティカルパスCSSジェネレーター

★使い方

①URLを入力

②ブロックしているCSS(ここでは common.css)の中身を全て貼り付ける。

③「Creat Critical Path CSS 」ボタンを押す。

④生成されたCSSを全て選択→コピーしておく。

CSSのインライン化

インライン化することで、ブラウザが直接コードを読むことができます。

先程コピーしたCSSコードをインライン化してみます。

<!DOCTYPE html>
<html lang="ja">
/* ~~~~省略~~~~ */
<head>
<style>/* ここに生成されたCSSコードを貼り付ける*/</style>
<link rel="stylesheet" type="text/css" href="/css/common.css"/> /* 共通デザイン */
<link rel="stylesheet" type="text/css" href="/css/home.css"/> /* TOPページ用デザイン */
<script type="text/javascript" src="/js/jquery-3.3.1.min.js"></script> /* 必須スクリプト */
<script type="text/javascript" src="/js/scroll.js"></script> /* なめらかスクロール */
</head>
<body>
/* ~~~~省略~~~~ */
</body>
</html>

5行目になります。

<style>@charset "UTF-8";html{background:#EFEFEF}body{text-align:center}header{height:60px;background-color:#FFF}header .header-inner{width:1260px;margin:0 auto}header .logo{margin-top:15px}footer{background-color:#EFEFEF;padding:60px 0}#Page{text-align:left;margin:0 auto;background:#FFFFFF;min-width:1260px}#Wrap{width:1260px;margin:0 auto}.contents-body{float:left;width:860px;margin:40px 0;padding:0 20px}#MainImage{margin:0 auto;display:none}#Copyright{font-size:12px;color:#999;width:1260px;margin:0 auto}#SideBox h2{font-weight:bold}nav{background-color:#EFEFEF}nav ul.nav-menu{width:1260px;margin:0 auto}nav .nav-menu li a{display:block;font-size:14px;padding:15px 40px;text-decoration:none;color:#000;font-weight:bold}#SideBox{float:right;width:240px;padding:60px}#NewsList{width:540px;float:left;margin-right:60px}#NewsList li{border-bottom:1px solid #CCC;margin-bottom:20px;list-style:none}#BaserFeed{width:260px;float:left}.img-eye-catch{float:left;margin-right:20px;margin-bottom:20px}.img-eye-catch{float:left;margin-right:20px;margin-bottom:20px}.widget{margin-bottom:60px}.widget-area h2{font-weight:bold;font-size:20px}.clearfix:after{content:" ";display:block;clear:both;height:0}.clearfix{display:inline-block}.clearfix{display:block}nav .nav-menu{display:block;position:relative;list-style:none;margin:0;padding:0;z-index:15}nav .nav-item{list-style:none;display:inline-block;padding:0;margin:0}nav .nav-item>a{position:relative;display:inline-block;padding:0.5em 1em;margin:0 0 -1px 0;border:1px solid transparent}nav .sub-nav{position:absolute;display:none;padding:20px;border:1px solid #dedede;background-color:#fff;z-index:1}#MainImage{z-index:0}nav .sub-nav ul{display:inline-block;vertical-align:top;margin:0 1em 0 0;padding:0}nav .sub-nav li{display:block;list-style-type:none;margin:0;padding:0}nav .ul-level-2 a{padding:10px 20px!important}.ul-level-2{margin-left:40px}#SearchIndexQ{width:95%}</style>
<style>生成された CSS コード</style>

この様なコードで囲む事でインライン化できます。

上記のサンプルソースでは、home.css もレンダリングをブロックしているので、common.css と同様にします。

<!DOCTYPE html>
<html lang="ja">
/* ~~~~省略~~~~ */
<head>
<style>@charset "UTF-8";html{background:#EFEFEF}body{text-align:center}header{height:60px;background-color:#FFF}header .header-inner{width:1260px;margin:0 auto}header .logo{margin-top:15px}footer{background-color:#EFEFEF;padding:60px 0}#Page{text-align:left;margin:0 auto;background:#FFFFFF;min-width:1260px}#Wrap{width:1260px;margin:0 auto}.contents-body{float:left;width:860px;margin:40px 0;padding:0 20px}#MainImage{margin:0 auto;display:none}#Copyright{font-size:12px;color:#999;width:1260px;margin:0 auto}#SideBox h2{font-weight:bold}nav{background-color:#EFEFEF}nav ul.nav-menu{width:1260px;margin:0 auto}nav .nav-menu li a{display:block;font-size:14px;padding:15px 40px;text-decoration:none;color:#000;font-weight:bold}#SideBox{float:right;width:240px;padding:60px}#NewsList{width:540px;float:left;margin-right:60px}#NewsList li{border-bottom:1px solid #CCC;margin-bottom:20px;list-style:none}#BaserFeed{width:260px;float:left}.img-eye-catch{float:left;margin-right:20px;margin-bottom:20px}.img-eye-catch{float:left;margin-right:20px;margin-bottom:20px}.widget{margin-bottom:60px}.widget-area h2{font-weight:bold;font-size:20px}.clearfix:after{content:" ";display:block;clear:both;height:0}.clearfix{display:inline-block}.clearfix{display:block}nav .nav-menu{display:block;position:relative;list-style:none;margin:0;padding:0;z-index:15}nav .nav-item{list-style:none;display:inline-block;padding:0;margin:0}nav .nav-item>a{position:relative;display:inline-block;padding:0.5em 1em;margin:0 0 -1px 0;border:1px solid transparent}nav .sub-nav{position:absolute;display:none;padding:20px;border:1px solid #dedede;background-color:#fff;z-index:1}#MainImage{z-index:0}nav .sub-nav ul{display:inline-block;vertical-align:top;margin:0 1em 0 0;padding:0}nav .sub-nav li{display:block;list-style-type:none;margin:0;padding:0}nav .ul-level-2 a{padding:10px 20px!important}.ul-level-2{margin-left:40px}#SearchIndexQ{width:95%}</style>
<link rel="stylesheet" type="text/css" href="/css/common.css"/>
<style>/* ここに生成されたCSSコードを貼り付ける(home.css)*/</style>
<link rel="stylesheet" type="text/css" href="/css/home.css"/>
<script type="text/javascript" src="/js/jquery-3.3.1.min.js"></script> /* 必須スクリプト */
<script type="text/javascript" src="/js/scroll.js"></script> /* なめらかスクロール */
</head>
<body>
/* ~~~~省略~~~~ */
</body>
</html>
実際のソースはかなり長くなります。

link rel=”preload” を追記する

次に、linkタグのrel属性の値を rel="preload" に変更し、as="style" を追記します。

<style>生成されたコード</style>
<link rel="preload" type="text/css" href="/css/common.css" as="style">

preload は、href 属性で指定したURLのコンテンツを先読みするための指定です。

これにより、レンダリングブロックを回避しながらCSSを読み込むことができます。

参考:rel="preload" によるコンテンツの先読み

これで解決できれば良いのですが、「preload」に対応していないブラウザがあります。

<link rel="preload"> ブラウザ対応状況

preload のブラウザ対応状況

Can I use でチェックした所、本記事作成時点では、IE および Firefox などに対応していません。

なので、rel=”preload” 未対応ブラウザにも、preload と同じ役割を持たす追記をしていきます。

loadCSS の導入

loadCSS という JavaScript を利用させて頂きます。

https://github.com/filamentgroup/loadCSS

こちらを利用するには、下記の JavaScript コード が必要になりますのでコピーしておきます。

https://github.com/filamentgroup/loadCSS/blob/master/src/cssrelpreload.js

実装方法

<head>
<style>インラインCSSコード</style>
<link rel="preload" href="/css/common.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/common.css"></noscript>
<script>
/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
/* This file is meant as a standalone workflow for
– testing support for link[rel=preload]
– enabling async CSS loading in browsers that do not support rel=preload
– applying rel preload css once loaded, whether supported or not.
*/
(function( w ){
"use strict";
// rel=preload support test
if( !w.loadCSS ){
w.loadCSS = function(){};
}
//以下全てを貼り付ける
</script>
</head>

解説

3行目:onload="this.onload=null;this.rel=’stylesheet'" の追記。

4行目:スクリプトが使えない環境時に読み込ませる代替CSS

6行目:MITライセンス表記。絶対に消してはいけません。

7~11行目:コードの説明。消してもOK

12行目:※メインスクリプト(縮小するのがおすすめ)

※スクリプトも CSS と同様に <script>コード</script> でインライン化できます。

以下、本記事で紹介しているサンプルコードになります。

レンダリングをブロックするCSSのインライン化と妨げにならないCSSの記述例

<!DOCTYPE html>
<html lang="ja">
/* ~~~~省略~~~~ */
<head>
<style>インラインCSSコード(common)</style>
<style>インラインCSSコード(home)</style>
<link rel="preload" href="/css/common.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/common.css"></noscript>
<link rel="preload" href="/css/home.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/home.css"></noscript>
<script>
/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
(function(a){if(!a.loadCSS){a.loadCSS=function(){}}var b=loadCSS.relpreload={};b.support=(function(){var d;try{d=a.document.createElement("link").relList.supports("preload")}catch(f){d=false}return function(){return d}})();b.bindMediaToggle=function(e){var f=e.media||"all";function d(){if(e.addEventListener){e.removeEventListener("load",d)}else{if(e.attachEvent){e.detachEvent("onload",d)}}e.setAttribute("onload",null);e.media=f}if(e.addEventListener){e.addEventListener("load",d)}else{if(e.attachEvent){e.attachEvent("onload",d)}}setTimeout(function(){e.rel="stylesheet";e.media="only x"});setTimeout(d,3000)};b.poly=function(){if(b.support()){return}var d=a.document.getElementsByTagName("link");for(var e=0;e<d.length;e++){var f=d[e];if(f.rel==="preload"&&f.getAttribute("as")==="style"&&!f.getAttribute("data-loadcss")){f.setAttribute("data-loadcss",true);b.bindMediaToggle(f)}}};if(!b.support()){b.poly();var c=a.setInterval(b.poly,500);if(a.addEventListener){a.addEventListener("load",function(){b.poly();a.clearInterval(c)})}else{if(a.attachEvent){a.attachEvent("onload",function(){b.poly();a.clearInterval(c)})}}}if(typeof exports!=="undefined"){exports.loadCSS=loadCSS}else{a.loadCSS=loadCSS}}(typeof global!=="undefined"?global:this));
</script>
</head>
<body>
/* ~~~~省略~~~~ */
</body>
</html>

5・6行目で、インラインCSSをまとめています。実際はかなり長くなります。

<style>common+home</style>と合体させずに、

<style>common</style><style>home</style> と分けてあげる方がメンテナンス性が良いです。
★トップページ以外は使用しないCSSなので。

11行目からの <script>~</script> の記述は1つでOKです。(各ページ毎に)

PageSpeed Insightsで再チェック

PageSpeed Insights

レンダリングブロックCSS OK

指摘されていた CSS の表示が消えました。

また、Firefox や IE でサイトが正しく表示されるかもチェックしましょう。

インライン化する上での注意点

インライン化には、ある程度の知識が必要です。
  • インライン化することで、CSSで指定している画像やウェブフォントなどのパスが変わり、表示されないことがあります。
  • CSSの圧縮方法でも触れましたが、縮小時にコードが崩れる事があります。

これらを直せる位の知識が必要になります。

また、ウェブサイトの種類によっては、全ページを手動で記述していく必要があったり・・デザイン変更時のメンテナンス性が悪くなります。

エレメント化テンプレ化 するなどして、メンテナンス性を落とさない工夫も必要かと思います。

最後に・・

レンダリングを妨げるリソースの除外という項目は、一番上に表示されるだけあってかなり重要な項目になっています。

改善できると、多くの方が体感できる位に表示速度が変わります。

次回は、レンダリングを妨げるリソースのJavaScript編をお届けします。

参考になれば幸いです。

スポンサーリンク