Edited at

PageSpeed Insightsで100点を取るためにやったこと

More than 1 year has passed since last update.


はじめに

内部SEOとして、PageSpeed Insightsで高得点をとる……なんて話を昔から、チラホラ聞きます。

ページ速度がSEOにどれほどの影響があるのかはわかりませんが、ページ表示速度の改善を行って悪いことはないはずなので、私が運営している個人サイトをPageSpeed Insightsで100点とれるように頑張ってみました。

本記事では、レンダリングブロック周りを主に取り扱っていきたいと思います。


目標


  • デザインは崩さない


    • よく見る対応として、「外部CSSをbodyの直後で読み込むようにして……」というのがあるけど、そうすると、一度CSSが当たらないページが出てしまう。美しくないので、ファーストビューではCSSが当たった状態で表示する



  • maxCDN等を利用している部分は、そのまま使う


    • 個人サイトなので、CDNを使用しているのはサードパーティー製のJSやCSSのみだが、これはこのまま使う



  • 無理をしてJS、CSSをまとめない


    • 外部CSSやJSを無理してまとめると、各ページ毎に作られることになり、ブラウザキャッシュが有効利用されにくい

    • HTTP2にすれば、同時接続の制限もなくなるし……




静的コンテンツをキャッシュさせる

画像、JS、CSSは最低2週間、できれば1年間キャッシュさせて下さい。

今回は、3週間にします。

PHPで出力している場合は、

<?php

header('Content-type: text/css');
header('Cache-Control: max-age='.(60 * 60 * 24 * 21).', public');
$path = 'xxxxxxx';
header('Last-Modified: '. date('F d Y H:i:s', filemtime($path)).' JST');
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= filemtime($path)) {
header('HTTP/1.1 304 Not Modified');
die;
}
echo file_get_contents($path);

Apacheの場合は、

    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript

ExpiresActive On
ExpiresByType text/css "access plus 3 week"
ExpiresByType text/javascript "access plus 3 week"
ExpiresByType application/javascript "access plus 3 week"
ExpiresByType application/x-javascript "access plus 3 week"
ExpiresByType image/jpeg "access plus 3 week"
ExpiresByType image/png "access plus 3 week"
ExpiresByType image/gif "access plus 3 week"
#フォント
ExpiresByType application/vnd.ms-fontobject "access plus 3 week"
ExpiresByType application/x-font-ttf "access plus 3 week"
ExpiresByType application/x-font-opentype "access plus 3 week"
ExpiresByType application/x-font-woff "access plus 3 week"
ExpiresByType image/svg+xml "access plus 3 week"
FileETag MTime Size

こんな感じ。

nginx の場合は、

location ~ ^/static_contents/ {

add_header Cache_Control "max-age=1814400, public";
}

こんな感じ。


レンダリングブロックしているJSをなんとかする

<script src="..."></script>はレンダリングブロックするので、PageSpeed Insightsに怒られます。

これをまずは、なんとかします。


とりあえず色々省略した元HTML

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>

<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<link rel="stylesheet" as="style" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css">
<link rel="stylesheet" as="style" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" as="style" href="//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

</head>
<body>

<div class="container-fluid">
<div class="row">
<form class="form-search subscribe-container" method="post" action="" role="form">
<div class="form-group"> <input type="text" value="" name="xxxxx" class="form-control input-lg url_input" placeholder="入力して下さい。" required> </div>
<div class="form-group"> <button type="submit" class="btn btn-success btn-lg btn-block">送信</button> </div>
<div class="form-group"> <label>スイッチ<br><input type="checkbox" value="yes" name="switch_a" class="boot-switch"></label> </div>
</form>
</div>
</div>

<script>
$(function() {
$('form').submit(function() {
$('form').find(':submit').attr('disabled', 'disabled');
});
});
</script>

<script src="//netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.min.js"></script>
<script>
$('.boot-switch').bootstrapSwitch();
</script>

<script src="//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.js"></script>

</body>
</html>


PageSpeed Insightsの解析結果

7a5a22fc1ce384ebcb386a264587aa11.png

解決方法としては、2つあり、asyncを付けるか、deferを付けるかのどっちかになります。



  • async


    • 非同期でJSを読み込み、可能な限りはやく実行




  • defer


    • 非同期でJSを読み込み、ページを最後まで読み込んだら順番に実行



asyncは、読み込まれると同時に実行されますので、実行順序は保証されません。

単体で解決しているならともかく、依存がある場合は使用できません。

deferはページが読み込み終わるまで実行されませんが、実行順序は保証されます。

JQuery使ってるし、Bootstrapも使ってるので、defer一択です。

読み込んでいる、Script全部に、deferを付けたら、実行順序も保証されるし、そのまま動くよね!

7fcf3bd5503b7089bfbd2d42e347ec5f.png

orz...動きませんでした。

deferすると、インラインで記述された依存コードが動かなくなります。

全部外に出すのはめんどくさいので、色々試してみたところ、

    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" onload="

$(function() {
$('form').submit(function() {
$('form').find(':submit').attr('disabled', 'disabled');
});
});
"
defer></script>

こんな感じで、scriptタグのonloadイベントの中に依存コードを入れれば、解決するっぽいです。

※あと、外部JSの中でdocument.writeしている場合もNGのようです。


変更後HTML

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>

<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<link rel="stylesheet" as="style" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css">
<link rel="stylesheet" as="style" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" as="style" href="//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.css">

</head>
<body>

<div class="container-fluid">
<div class="row">
<form class="form-search subscribe-container" method="post" action="" role="form">
<div class="form-group"> <input type="text" value="" name="xxxxx" class="form-control input-lg url_input" placeholder="入力して下さい。" required> </div>
<div class="form-group"> <button type="submit" class="btn btn-success btn-lg btn-block">送信</button> </div>
<div class="form-group"> <label>スイッチ<br><input type="checkbox" value="yes" name="switch_a" class="boot-switch"></label> </div>
</form>
</div>
</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" onload="
$(function() {
$('form').submit(function() {
$('form').find(':submit').attr('disabled', 'disabled');
});
});
"
defer></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" defer></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.min.js" onload="$('.boot-switch').bootstrapSwitch();" defer></script>

<script src="//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.js" defer></script>

</body>
</html>

点数は変わりませんが、JSのエラーは消えました。

9ec682d1a3fb6bb6c9d69c6e2e21e86f.png


CSSを遅延レンダリングさせる

CSSはHTML単体で、どうにかする方法はないので、AsyncとDeferを行う事ができる、JSを作ってみました。

DLはこちら⇒PrefetchLoader

使い方は簡単。

今回の場合であれば、

<script src="/js/PrefetchLoader.js" async onload="

(function () {
var prefetch = new PrefetchSequence(
[
{
urls: [
'//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css',
'//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css',
'//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css',
],
default_resource: 'style',
using_defer_css_load: true // deferで読み込む
},
{
urls: [
'//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css',
'//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.css',
],
default_resource: 'style',
using_async_css_load: true // asyncで読み込む
}
]

);
prefetch.allAsync();

}());

"></script>
<noscript>
<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<link rel="stylesheet" as="style" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css">
<link rel="stylesheet" as="style" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" as="style" href="//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.css">
</noscript>

このJSは、単独で動作するので、asyncで読み込みます。

やってることは、

preloadもしくはprefetchを利用してCSSを非同期で読み込み、読み込み終わったら、レンダリングさせているだけです。

これでCSSの遅延読み込みは完了!

9b744b189450c1b48fd4ca64c4aad556.png

と思いきや、デザインが崩れてしまいました。

どうやら、CSSを非同期にしたことで、CSSに依存したインラインJSがおかしくなったようです。

具体的には

    <script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.min.js" onload="$('.boot-switch').bootstrapSwitch();" defer></script>

これ。ここの部分。

これを解決するには、CSSが適応されてから、onloadに指定したJSを実行してやればいいので、

  <script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.min.js" defer onLoad="

window.addEventListener('load', function(){
$('.boot-switch').bootstrapSwitch();
}, false );
"
></script>

こんな感じで書けば、問題なくなった。

もしくは、PrefetchLoaderpreload_successでやるか。

a67404f6b119dec90329e426967aa6e0.png

……あれ?

むしろ点数下がっているんですが……?

しかも、CSSのレンダリングブロックが解除されていないし、なんかエラーも増えてる。

そして、増えたエラーメッセージはこれ。

c3e0f00b33adfbc75dc034ac05b094e0.png

エラーメッセージを読むと、


非同期読み込んでるCSSってやっぱりレンダリングに必要だったんじゃない?

5%しかレンダリングできなかったよ?


ってことですね。

図らずも、目標として掲げた、「ファーストビューでキチンとstyleを当てる」という事をやれば、解決しそうですね。

とはいえ、使用しているCSSをすべてインラインにするのは現実的ではありません。

ファーストビューで、適応されているCSSだけ抜き取ってインラインCSSにしたい。

そこで、gulp-uncssを使います。

npmがインストールされていれば、

↓のpackage.jsonを配置して、npm installするだけ。


package.json

{

"name": "",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": ""
},
"keywords": [
],
"author": "Suzunone",
"license": "",
"homepage": "",
"devDependencies": {
"gulp": "^3.9.1",
"gulp-uncss": "^1.0.6"
}
}

つぎに、ページで読み込まれているCSSすべて一纏めにして、package.jsonを配置したディレクトリに、site.cssとして配置します。

そして、以下のgulpfile.jsを、同じディレクトリに配置します。


gulpfile.js

var gulp = require('gulp');

var uncss = require('gulp-uncss');

gulp.task('default', function () {
return gulp.src('site.css')
.pipe(uncss({
html: ['https://xxxxxxxxx/test.html'] //ここは任意のurlにして下さい
}))
.pipe(gulp.dest('./out/'));
});


ディレクトリ構造は、こんな感じになります。

├── gulpfile.js

├── node_modules
├── package.json
└── site.css

配置し終わったら、

gulp

とコマンドを実行すると、ファーストビューで使用されるCSSだけが、outディレクトリに書き出されます。

├── gulpfile.js

├── node_modules
├── out
│   └── site.css
├── package.json
└── site.css

書き出されたCSSを

内に、インラインで記述する。

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>

<script src="/js/PrefetchLoader.js" async onload="
(function () {
var prefetch = new PrefetchSequence(
[
{
urls: [
'//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css',
'//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css',
'//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css',
],
default_resource: 'style',
using_defer_css_load: true
},
{
urls: [
'//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css',
'//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.css',
],
default_resource: 'style',
using_async_css_load: true
}
]

);
prefetch.allAsync();

}());

"></script>
<noscript>
<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" as="style" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<link rel="stylesheet" as="style" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css">
<link rel="stylesheet" as="style" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" as="style" href="//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.css">
</noscript>
<style>
html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}button,input{margin:0;font:inherit;color:inherit}button{overflow:visible}button{text-transform:none}button{-webkit-appearance:button;cursor:pointer}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input{font-family:inherit;font-size:inherit;line-height:inherit}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=checkbox]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-group{margin-bottom:15px}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active:focus,.btn-success:active:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success:active{background-image:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-block{display:block;width:100%}.container-fluid:after,.container-fluid:before,.row:after,.row:before{display:table;content:" "}.container-fluid:after,.row:after{clear:both}@-ms-viewport{width:device-width}
.btn-success{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-success:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active{background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success:active{background-color:#419641;border-color:#3e8f3e}
body{position:relative}body{padding-top:50px}.url_input{border:1px solid #FF8000}
.bootstrap-switch{display:inline-block;direction:ltr;cursor:pointer;border-radius:4px;border:1px solid #ccc;position:relative;text-align:left;overflow:hidden;line-height:8px;z-index:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.bootstrap-switch .bootstrap-switch-container{display:inline-block;top:0;border-radius:4px;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on,.bootstrap-switch .bootstrap-switch-label{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:inline-block!important;height:100%;padding:6px 12px;font-size:14px;line-height:20px}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on{text-align:center;z-index:1}.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary{color:#fff;background:#337ab7}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default{color:#000;background:#eee}.bootstrap-switch .bootstrap-switch-label{text-align:center;margin-top:-1px;margin-bottom:-1px;z-index:100;color:#333;background:#fff}.bootstrap-switch .bootstrap-switch-handle-on{border-bottom-left-radius:3px;border-top-left-radius:3px}.bootstrap-switch .bootstrap-switch-handle-off{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch input[type=checkbox]{position:absolute!important;top:0;left:0;margin:0;z-index:-1;opacity:0;filter:alpha(opacity=0)}.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label{border-bottom-left-radius:3px;border-top-left-radius:3px}
</style>

</head>
<body>

<div class="container-fluid">
<div class="row">
<form class="form-search subscribe-container" method="post" action="" role="form">
<div class="form-group"> <input type="text" value="" name="xxxxx" class="form-control input-lg url_input" placeholder="入力して下さい。" required> </div>
<div class="form-group"> <button type="submit" class="btn btn-success btn-lg btn-block">送信</button> </div>
<div class="form-group"> <label>スイッチ<br><input type="checkbox" value="yes" name="switch_a" class="boot-switch"></label> </div>
</form>
</div>
</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" onload="
$(function() {
$('form').submit(function() {
$('form').find(':submit').attr('disabled', 'disabled');
});
});
"
defer></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" defer></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.min.js" defer onLoad="
window.addEventListener('load', function(){
$('.boot-switch').bootstrapSwitch();
}, false );
"
></script>

<script src="//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.js" defer></script>

</body>
</html>

370ecc7967efee506783d7d8e9469c87.png

83913086c21effb4b4566715c9bae436.png

やったぜ。


画像を圧縮(最適化)する

幸いながら、動的に画像が増えるような機能はないため、皆大好きtinypng(怪しいパンダのアイツ)で何とかなりました。

動的に最適化する場合は、Google推奨の方法で対応して下さい。


最後に

実際には、サードパーティー製の解析タグや、広告タグがあり、100点を取ることは不可能かも知れませんが、かなり近づけることはできると思います。

そして、キチンと対応すると、確かに表示速度は速くなりました。

サーバーのレスポンスタイムは変わらなくても、体感的に早くなった気がします。

(プラシーボ効果かもしれませんが)

今回作った、PrefetchLoader.jsは、CSSの遅延ロード以外にもコンテンツの先読みに使用できますので、より一層の早さを目指すなら、

(function () {

var prefetch = new PrefetchSequence(
[
{
urls: [
'//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css',
'//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css',
'//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css',
],
default_resource: 'style',
using_defer_css_load: true
},
{
urls: [
'//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css',
'//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.css',
],
default_resource: 'style',
using_async_css_load: true
},
{
urls: [
'//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js',
'//netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js',
'//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.min.js',
'//cdn.jsdelivr.net/sweetalert2/6.6.2/sweetalert2.min.js'
],
default_resource: 'script',
}
]

]

);
prefetch.allAsync();

}());

こんな感じで、HTMLの最後で読み込まれるJSを先読みさせたり、

画像のlazyLoadを行っている場合に、

window.addEventListener( 'load', function(){

var prefetch = new PrefetchLoader({
href_attribute_name:'data-src'
});
prefetch.all('img[data-src]');

}, false );

こんな感じで、通信の余剰を使って、先に画像を読み込んだりできます。

是非試してみて下さい。

プルリクもお待ちしております。


更新履歴


  • Apacheの設定にフォントの設定が抜けていました