ブログを高速化しました

2023/09/062
アイキャッチ

ここ2週間ほど、ブログを軽量高速化するべく色々と試行錯誤していました。

で、その結果がこちら…

PSI pc
PSI mobile

PageSpeed Insights

モバイルスコアが60前後 → 90前後まで向上しました!

たぶん、何も弄ってないプレーンな状態の QooQ とほぼ変わりないんじゃないですかね。

今までコツコツと自分好みにカスタマイズしてきた見た目や機能を犠牲にすることなく、ここまで改善できるとは思いませんでした。

ということで、その改善内容をまとめておこうと思います。

試される場合は、必ずテーマのバックアップを取ってから行って下さい。

CONTENTS

bundle.css の無効化、及びインライン化

Blogger のテーマ(特に旧バージョン)は、css_bundle_v2.css(リンクはブログのソースコードを見れば上の方にあると思います) という基本スタイルシートの外部ファイルを強制的に読み込む仕様になっていて、これがスコアを下げる要因の一つになっています。なのでまずはこれを読み込ませないようにしました。

手順は簡単で、HTML 編集で <html> タグ内に  b:css='false' を追加するだけです。

<html b:css='false' b:version='2' class='v2' expr:dir='data:blog.languageDirection' expr:lang='data:blog.locale' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'>

このままではレイアウトが崩れるところが出てくるので、bundle.css の中身を HTML 内に直接コピペするわけですが、ほぼ使わないようなガジェットに関するものだったり、少なくともウチでは不要なものだらけ…というわけで、レイアウトに影響ないかを一つ一つ確認しながら取捨選択し、必要最小限まで絞り込んだ結果、かなりの量を減らせました。(結構根気のいる地道な作業です。オンラインのコード整形サービス等で見やすくしてからやった方が効率がいいです)

ちなみに、わざわざ取捨選択せずに中身丸ごとそのままインラインで書いただけでもスコアは向上します。(これが一番手っ取り早くて安全ですw)
※必ず <b:skin><![CDATA[ 直下に書いてください。

追記: 丸ごとコピペだとエラーになる場合があります。そのような時は、コード内の以下の部分を削除してみてください。(消しても特に影響はないはず…)

.share-buttons li .platform-sharing-text{margin-$startSide:56px}{"version":3,"sourceRoot":"","sources":["../../../../../../../../../../../java/com/google/blogger/b2/staticresources/layouts/skins/responsive/scss/common.scss","../../../../../../../../../../../java/com/google/blogger/b2/staticresources/layouts/skins/responsive/scss/_variables.scss","../../../../../../../../../../../java/com/google/blogger/b2/staticresources/layouts/skins/responsive/scss/sharing.scss","../../../../../../../../../../../java/com/google/blogger/b2/layouts/widgets/sharing/sharing.scss"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AASF;AAAA;EALE;EACA;EACA;;;AAQF;EACE;;;AA2FF;EACE,kBAJY;EAKZ;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAaF;EACE;;;AAGF;AAAA;EAEE,MCnHmB;EDoHnB;;;AEvIF;AAAA;AAAA;AAAA;AASA;AAWA;AACA;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;AAAA;EAEE,MAjCmB;;;AAoCrB;AAAA;EAEE;;;AAGF;EACE,kBA3CyB;EA4CzB;EACA;EAEA,OA9CmB;EA+CnB;EACA;EACA;EACA;EACA;AACA;AACA;EACA,WAhDwB;EAiDxB,SCxEsB;;;AD2ExB;EACE;;;AAGF;EFlCE;EACA;EACA;EACA;EACA;EEgCA;;;AAGF;EACE;EACA,QA9D0B;;;AAiE5B;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAGF;AACA;AAAA;EAEE;EACA;;;AAGF;EACE;EACA;AACA;EACA,aAvG0B;EAwG1B;;;AAGF;EACE,mBAzG0B","file":"sharing_css.css"}

条件分岐で CSS を 最適化

<b:skin>~</b:skin> 内の CSS はどのページでも常に読み込まれるわけですが、条件分岐タグを駆使して必要な所で必要な CSS だけを読み込ませるようにしました。

特定の条件でしか使わないような CSS は </b:skin> より下のところに書きます。
※テーマデザイナーは使えなくなりますので、$(font.color) のような変数プロパティは #000 のようなカラーコードに直してください。

例えば、記事一覧ページ(つまり個別ページ以外すべて)用と個別ページ用の CSS をそれぞれ分けて書く場合はこんな感じ。

<b:skin><![CDATA[
/*常に読み込む CSS*/
]]></b:skin>
<b:if cond='!data:view.isSingleItem'>
<style>
/* 記事一覧用の CSS */
<style>
<b:else/>
<style>
/* 個別ページ用の CSS */
<style>
</b:if>

 HTML/Javascript ウィジェット用の CSS も同様に振り分けたり、ウィジェット内に書くようにしてあります。

Font Awesome のインライン SVG 化

これも基本的に bundle.css の場合と同じで、JavaScript や CSS の CDN ファイルを外部から読み込ませず、ダウンロードした SVG コードを直接書くようにしました。

今までは を表示させるためには、予め HTML 内に JavaScript または CSS の CDN リンクを置いた状態で、表示させたい位置に <i class="fas fa-external-link-alt"></i>  のようなタグを挿入していましたが、インライン SVG ならば以下のようなコードを挿入するだけで表示されるようになります。

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z"/></svg>

SVG の便利な使い方

同じ SVG を使い回す場合や、長ったらしいコードが嫌というような方は use タグを使う方法がオススメです。詳しくはこちらを。

ファビコンQiita
サムネイル
SVGをuseタグで使いまわす - Qiita
https://qiita.com/mzzzk/items/8bb2623d78c8444bbbef

入れ替え作業

bundle.css の作業より大変でしたw
HTML内のアイコンを置き換えるのは大したことはないものの、記事内で使ってるアイコンが思ったよりも多くて…新Bloggerの記事編集に置き換え機能が付いたお陰でだいぶ捗りはしたものの、エラい時間かかりました(~_~;)

ライセンス表記

尚、このようにダウンロードしたアイコンコードを個別に使用する場合は、HTML内や専用ページ内等にライセンスを記載しておいたほうが無難なようです。詳しくはこちらを。

ファビコンバグ取りの日々
サムネイル
FontAwesomeをSVGで使用する【JavaScriptなし】
はじめに 「FontAwesomeをJavaScriptなしで使用する方法」または、「FontAwesomeの一部のアイコンを使用する方法」です。 JavaScript無効環境でFontAwesomeを使用したページを閲覧すると文字化けしたような表示になるのを目にします。そうなる...
https://www.bugbugnow.net/2019/05/use-font-awesome-with-svg.html

2021/02/28 追記:トップページのサムネイル画像をWebPに変換

Pagespeed Insights で指摘される「次世代フォーマットの画像の使用」に関する対応をすることにしました。
トップページで表示されるサムネイル画像の圧縮形式を、JPEG等と同等の画質でも圧縮率が高くサイズの小さいWebPに変換させることによりスコアが向上します。
Bloggerの画像は URL のパラメータを少し書き換えるだけでWebP化できるのですが、IB-Note さんが自動で変換してくれる JavaScript を作られ、早速導入してみました。

導入方法はこちらの記事をご参照ください。
尚、テーマによってはコードの書き換え箇所や手順が異なる場合があるので要注意です。

ファビコンIB-Note
サムネイル
アイキャッチ画像をWebPに一括変換する方法 | IB-Note
Bloggerでトップページの投稿画像をWebPに一括変換する方法をご紹介します。
https://itblogger-note.blogspot.com/2021/02/blogger-image-webp.html

QooQ カード版での導入手順

参考までに QooQ の「カード版」での導入手順を書いておきます。
ちなみに「リスト版」の方は画像表示部分の構造が多少異なります。まあこちらに関しては、元々サムネ画像のサイズが小さいので無理にWebP化する必要はないと思います(^^;

2021/09/25 追記: QooQ リスト版での導入方法

mizusame さんがリスト版での導入手順記事を書かれました。リスト版ユーザーの方はご参考にどうぞ。

ファビコンmizusame
サムネイル
【QooQ】list 版記事一覧のサムネイルの WebP 化とサイズ変更
Blogger テンプレート「QooQ」の list 版の記事一覧のサムネイルは 72 px × 72 px と、サイズが小さめです。ただサイズを変更するだけなら Blogger の resizeImage() 関数を使えばできますが、サイズを大きくすると、どうしてもページの...
https://mizunosame.blogspot.com/2021/09/qooq-list-thumbnails-webp-resize.html

HTMLを編集しますので必ず予めバックアップを取ってから行って下さい。もしくはテスト用の環境(別ブログ)を用意してそちらで試されることをおすすめします。
これから説明をするのは何も弄っていないプレーンな状態の QooQ での手順です。すでにテーマの当該部分を弄られている環境では、タグの挿入位置が異なっていたり、コードの修正等の追加作業が必要になる場合がありますので各自でご対応ください。

手順①

まず以下のコードを検索で見つけます。

<div id='list'>

この下にある <b:loop> タグを以下のように書き換えます。

<b:loop index='i' values='data:posts' var='post'>
HTML
↓↓
HTML2

手順②

以下の文字列を検索で見つけます。

img class='list-item-img'

この前後を含めた5行のコードを以下のコードと入れ替えます。

<b:if cond='data:post.thumbnailUrl'>
<a expr:href='data:post.url'>
<img class='list-item-img' expr:src='resizeImage(data:post.firstImageUrl, 480, &quot;2:1&quot;)'/>
</a>
</b:if>
↓↓

2022/03/16: IB-Note さんのコードが新URL対応版にアップデートされましたので、こちらのコードもそれに合わせて変更しました。

<b:if cond='data:post.thumbnailUrl'>
<a expr:href='data:post.url'>
<picture class='list-item-img'>
<noscript><img expr:src='resizeImage(data:post.thumbnailUrl, 480,&quot;2:1&quot;)' height='240' loading='lazy' width='480'/></noscript>
</picture>
</a>
<script>
(function() {
const idx = "<data:i/>";
let imgurl = "<data:post.thumbnailUrl/>";
let imgurl_webp;
if (imgurl.match(/\/s[0-9]+-.*\//)) { // 旧URL
imgurl_webp = imgurl.replace(/\/s[0-9]+-.*\//, '/w480-h240-n-rw/');
imgurl = imgurl.replace(/\/s[0-9]+-.*\//, '/w480-h240-n/');
} else if (imgurl.match(/=s[0-9]+-.*$/)) { // 新URL
imgurl_webp = imgurl.replace(/=s[0-9]+-.*$/, '=w480-h240-n-rw');
imgurl = imgurl.replace(/=s[0-9]+-.*$/, '=w480-h240-n');
} else if (imgurl.match(/default.jpg/)) { // YouTubeサムネ対策
imgurl = imgurl.replace('default.jpg', 'mqdefault.jpg');
imgurl_webp = imgurl.replace('/vi/', '/vi_webp/').replace('.jpg', '.webp');
} else { //例外処理
imgurl_webp = "<data:post.firstImageUrl/>"
imgurl = imgurl_webp;
}
let eyecatch = document.getElementsByClassName('list-item-img')[idx];
let html = '';
html += '&lt;source srcset="' + imgurl_webp + '" type="image/webp"/&gt;';
html += '&lt;img alt="アイキャッチ" loading="lazy" width="480" height="240" src="' + imgurl + '"/&gt;';
eyecatch.innerHTML = html;
})();
</script>
<b:else/>
<!-- No Image 画像 -->
<a expr:href='data:post.url'>
<picture class='list-item-img'>
<source srcset='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgXR9QkxRwLIjXhLiYOj5aFHAUWAePYHRWxVpYYF27vmzrN6ysSdQP58uT9BRnGIb_Y3z9J_xKYcwvK0sEshtehjx0TE6Wo3Wt0LhxTfunT6rZVjYOzNRLMAULlcDTLQjzOpiXgvUEQog/w480-h240-n-rw/noimage.png' type='image/webp'/>
<img alt='アイキャッチ' loading='lazy' width='480' height='240' src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgXR9QkxRwLIjXhLiYOj5aFHAUWAePYHRWxVpYYF27vmzrN6ysSdQP58uT9BRnGIb_Y3z9J_xKYcwvK0sEshtehjx0TE6Wo3Wt0LhxTfunT6rZVjYOzNRLMAULlcDTLQjzOpiXgvUEQog/w480-h240-n/noimage.png'/>
</picture>
</a>
</b:if>

画像アスペクト比は QooQ 標準の 2:1 (480×240px)になっていますので、変更されている場合は各環境に合わせて w480-h240 の数値を調整してください。

No Image 画像はご自身で用意されたものを使われる場合は <source> と <img> それぞれURLを入れ替えてください
<source> の方のURLのサイズパラメータは末尾に -rw を付けて w480-h240-n-rw という風に書き換えてください。

2021/03/11 追記: widget.js の無効化

bundle.css と同じく自動的に読み込まれてしまう Blogger 標準の JavaScript である widget.js を無効化させました。

実はこれを実行すると一部のウィジェット等が機能しなくなってしまい、特にコメント投稿者のアイコンが表示されなくなってしまうことがネックで無効化を躊躇していたのですが、IB-Note さんに詳細な解説記事を書いていただいたお陰で解決する事ができました!
詳細についてはこちらの記事を御覧ください。

ファビコンIB-Note
サムネイル
Bloggerのコメントを標準JSなしで実現 | IB-Note
Bloggerのコメントを、標準JSなしで自然に表示する方法についてご紹介します。
https://itblogger-note.blogspot.com/2021/03/blogger-comment-without-js.html

また、うちよりも更にガッツリと高速化に取り組まれたことに関して纏められていますので、こちらの記事も合わせてどうぞ。

ファビコンIB-Note
サムネイル
ブログを限界まで高速化してみた | IB-Note
考えうる限りの手を尽くし、ブログを限界まで高速化してみました。
https://itblogger-note.blogspot.com/2021/03/blogger-speedup.html

widget.js 無効化による影響

当ブログでの唯一の影響として記事内画像のライトボックス表示ができなくなるという問題がありますが、これに関しては自分では然程気にしていません(^^;

2021/03/13 追記: jQuery に defer を追加

高速化に立ちはだかるラスボス(?)とも言える jQuery ですが、やはり外したくはないので、取り敢えずの対策として読み込みのタイミングを遅らせる defer 属性を <script> タグ内に付けてみることにしました。(async よりもJS実行のタイミングが遅いらしい?)

<script defer='defer' src='//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js'/>

試してみた結果、当ブログで jQuery を使っているジャンプボタンやスムーススクロールやコピーボタンが軒並み動かなくなってしまった…
デベロッパーツールで確認してみた所、どうやら $ is not defined というエラーが出ているのが原因らしい。
調べてみたらこちらのサイトに詳しい解説があり、手順通りにやってみたら無事解決しました。

jQueryで $ is not define エラーが出たときの一番簡単な解決法 | PisukeCode - Web開発まとめ

手順は簡単でスクリプトコードをちょっと書き換えるだけ。
例えばジャンプボタンならこのように書き換えます。

$(function(){var a=$("#pagetop");var b=$("#pagebottom");$(window).scroll(function(){if($(this).scrollTop()>800){a.fadeIn()}else{a.fadeOut()}if($(this).scrollTop()>0&&$(this).scrollTop()<$(document).height()-1200){b.fadeIn()}else{b.fadeOut()}});a.click(function(){$("body, html").animate({scrollTop:0},1000)});b.click(function(){$("body, html").animate({scrollTop:$(document).height()},1000)})});
↓↓
window.addEventListener('DOMContentLoaded', function(){var a=$("#pagetop");var b=$("#pagebottom");$(window).scroll(function(){if($(this).scrollTop()>800){a.fadeIn()}else{a.fadeOut()}if($(this).scrollTop()>0&&$(this).scrollTop()<$(document).height()-1200){b.fadeIn()}else{b.fadeOut()}});a.click(function(){$("body, html").animate({scrollTop:0},1000)});b.click(function(){$("body, html").animate({scrollTop:$(document).height()},1000)})});

これでついに jQuery も攻略しましたw
で、気になる計測結果は…

Pagespeed Insights:

Pagespeed Insights スコア
Lighthouse
Lighthouse スコア

ふじろじっく史上最高スコアが出ました!\(^o^)/

そして何より驚いたのが Test My Site での計測結果。

Test My Site 計測結果

今回の jQuery 対応を施すまでずっと2.5秒前後で遅いと評価されていたのが、一気に1秒も縮まった!
数値だけでなく実際の体感でもかなり早くなった感じがします。

ちなみにうちはPC環境だけでスマホはありませんが、ガラケーで当ブログにアクセスしてみたら、一部の画像等は表示できないものの、読み込みも早くてそこそこ問題なく見られるようになってましたw