はじめに
内部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の解析結果
解決方法としては、2つあり、async
を付けるか、defer
を付けるかのどっちかになります。
-
async
- 非同期でJSを読み込み、可能な限りはやく実行
-
defer
- 非同期でJSを読み込み、ページを最後まで読み込んだら順番に実行
async
は、読み込まれると同時に実行されますので、実行順序は保証されません。
単体で解決しているならともかく、依存がある場合は使用できません。
defer
はページが読み込み終わるまで実行されませんが、実行順序は保証されます。
__JQuery__使ってるし、__Bootstrap__も使ってるので、defer
一択です。
読み込んでいる、Script全部に、defer
を付けたら、実行順序も保証されるし、そのまま動くよね!
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のエラーは消えました。
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の遅延読み込みは完了!
と思いきや、デザインが崩れてしまいました。
どうやら、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>
こんな感じで書けば、問題なくなった。
もしくは、__PrefetchLoader__のpreload_success
でやるか。
……あれ?
むしろ点数下がっているんですが……?
しかも、CSSのレンダリングブロックが解除されていないし、なんかエラーも増えてる。
そして、増えたエラーメッセージはこれ。
エラーメッセージを読むと、
非同期読み込んでるCSSってやっぱりレンダリングに必要だったんじゃない?
5%しかレンダリングできなかったよ?
ってことですね。
図らずも、目標として掲げた、___「ファーストビューでキチンとstyleを当てる」___という事をやれば、解決しそうですね。
とはいえ、使用しているCSSをすべてインラインにするのは現実的ではありません。
ファーストビューで、適応されているCSSだけ抜き取ってインラインCSSにしたい。
そこで、gulp-uncssを使います。
npmがインストールされていれば、
↓のpackage.jsonを配置して、npm install
するだけ。
{
"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を、同じディレクトリに配置します。
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>
やったぜ。
画像を圧縮(最適化)する
幸いながら、動的に画像が増えるような機能はないため、皆大好き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の設定にフォントの設定が抜けていました