Google Bloggerのカスタマイズ備忘録ー9:高速化は難しい

0

Google Bloggerのカスタマイズ備忘録ー9
Google Bloggerのカスタマイズ備忘録ー9
 ブログパーツの見直しを行ったので、ブログの高速化にも着手してみました。 あれこれイジると不具合も発生するので、テスト用ブログを作って実施した内容が上手く機能するかを確認していました。

Vaster2の導入とカスタマイズ その9

 色々な見直しを行う前の状態では、PageSpeed Insightによるモバイル表示のパフォーマンスが45点で不合格状態でした。 この値は2026年1月のテーマで計測してあります。
対策前のパフォーマンスは45点
対策前のパフォーマンスは45点

 本記事に記載の機能追加と高速化対策によりモバイル表示のパフォーマンスが67点まで向上しました。 決して高い値ではないのですが、これ以上は手軽に実施できそうなネタがないので「一応」打ち止めとしました。
対策後のパフォーマンスは67点
対策後のパフォーマンスは67点

ソースコードコードを見易くするスクリプトを導入

 今まではソースコードの表示は<pre></pre>機能だけを使ってそっけない表示でしたが、自分自身でも判り難いので、0kuwa様のブログ で紹介している SyntaxHighlighter を導入してソースコードを見易く表示させる様にしました。

使い方は今までとほぼ同じで、
<div class="source_code_box">
<pre><code>
エスケープ変換済みのソースコード
:
:
</code></pre>
</div>
としていたのを
<pre class="brush:java" title="たいとる">
エスケープ変換済みのソースコード
:
:
</pre>
に変更するだけです。

導入には下記コードを</body>の上あたりに入れる必要があります。
テーマに追加したコード(</body> の上)
<!-- 記事ページの時だけ SyntaxHighlighte を読み込む -->
<b:if cond='data:blog.pageType == &quot;item&quot;'>

<!-- SyntaxHighlighter 追加 -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shCore.js"/>
<!-- autoloader対応 -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shAutoloader.js"/>
<!-- /HTMLと他言語を同時にハイライト対応用(html-script: true) -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shBrushXml.js"/>
<!-- テーマの読み込み(shCore.css内包版) -->
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/styles/shCoreFadeToGrey.css" />
<script language='javascript' type='text/javascript'>
var shCdnUrlStr='https://cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83';
SyntaxHighlighter.autoloader(
'actionscript3 as3      '+shCdnUrlStr+'/scripts/shBrushAS3.js',
'bash shell             '+shCdnUrlStr+'/scripts/shBrushBash.js',
'coldfusion cf          '+shCdnUrlStr+'/scripts/shBrushColdFusion.js',
'cpp c                  '+shCdnUrlStr+'/scripts/shBrushCpp.js',
'c# c-sharp csharp      '+shCdnUrlStr+'/scripts/shBrushCSharp.js',
'css                    '+shCdnUrlStr+'/scripts/shBrushCss.js',
'delphi pascal pas      '+shCdnUrlStr+'/scripts/shBrushDelphi.js',
'diff patch             '+shCdnUrlStr+'/scripts/shBrushDiff.js',
'erlang erl             '+shCdnUrlStr+'/scripts/shBrushErlang.js',
'groovy                 '+shCdnUrlStr+'/scripts/shBrushGroovy.js',
'html xml xhtml xslt    '+shCdnUrlStr+'/scripts/shBrushXml.js',
'java                   '+shCdnUrlStr+'/scripts/shBrushJava.js',
'javafx jfx             '+shCdnUrlStr+'/scripts/shBrushJavaFX.js',
'javascript js jscript  '+shCdnUrlStr+'/scripts/shBrushJScript.js',
'perl pl                '+shCdnUrlStr+'/scripts/shBrushPerl.js',
'php                    '+shCdnUrlStr+'/scripts/shBrushPhp.js',
'text plain             '+shCdnUrlStr+'/scripts/shBrushPlain.js',
'powershell ps          '+shCdnUrlStr+'/scripts/shBrushPlain.js',
'python py              '+shCdnUrlStr+'/scripts/shBrushPython.js',
'ruby rails ror         '+shCdnUrlStr+'/scripts/shBrushRuby.js',
'scala                  '+shCdnUrlStr+'/scripts/shBrushScala.js',
'sql                    '+shCdnUrlStr+'/scripts/shBrushSql.js',
'vb vbnet               '+shCdnUrlStr+'/scripts/shBrushVb.js'
);
SyntaxHighlighter.config.bloggerMode = true; // Blogger対応
SyntaxHighlighter.defaults['toolbar'] = false; // 「?」表示
SyntaxHighlighter.defaults['auto-links'] = false; // 自動リンク
//不具合が起きる為コメント化。使用時はpre側で要記述。
//SyntaxHighlighter.defaults['html-script'] = true; //HTMLと他言語を同時にハイライト
SyntaxHighlighter.defaults['tab-size'] = 2; //tabインデント量
// コード表示させるタグ名(デフォルト"pre")
// SyntaxHighlighter.config.tagName="";
SyntaxHighlighter.all();
</script>
<style>
.syntaxhighlighter {
  font-size: 14px !important; /* フォントサイズ */
  margin: 0.5em 0em 0.5em 0em !important; /* 上下空き */
  border: 1px solid #bbbbbb !important; /* 罫巻 */
  /* 角丸 */
  -webkit-border-radius: 10px !important;
  -moz-border-radius: 10px !important;
  -ms-border-radius: 10px !important;
  -o-border-radius: 10px !important;
  border-radius: 10px !important;
  max-height: 400px !important; /* 表示したい高さ */
}
.syntaxhighlighter table caption {
  padding: 0.3em 0 0.1em 1em !important; /* タイトルpadding */
  color: #ffffee !important; /* タイトル文字色 */
  background-color: #666666 !important; /* タイトル背景色 */
}
.syntaxhighlighter, .syntaxhighlighter div,
.syntaxhighlighter code, .syntaxhighlighter span {
  line-height: 1.2em !important; /* 行間 */
}
.syntaxhighlighter table td.code {
  padding: 0.3em 0 !important; /* コードエリアのpadding */
}
.syntaxhighlighter {
  background-color: #222222 !important; /* コード背景色 */
}
.syntaxhighlighter .line.alt1 {
  background-color: #222222 !important; /* コード偶数行背景色 */
}
.syntaxhighlighter .line.alt2 {
  background-color: #333333 !important; /* コード奇数行背景色 */
}
.syntaxhighlighter .comments, .syntaxhighlighter .comments a{
    color: #88eeee !important; /* コメント色 */
}
.syntaxhighlighter .preprocessor {
  color: #88eeee !important; /* #以降の色 */
}
.syntaxhighlighter .value {
  color: #00cc00 !important; /* 代入数字色 */
}
.syntaxhighlighter .keyword {
  color: #ff0000 !important; /* キーワード色 */
}
.syntaxhighlighter .script {
  font-weight: bold !important;
  color: #ff0000 !important; /* スクリプト色 */
  background-color: none !important;
}
.syntaxhighlighter.nogutter td.code .container textarea,
.syntaxhighlighter.nogutter td.code .line {
  padding-left: 1em !important; /* 行番号非表示時左空き量 */
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
  background-color: #114466 !important; /* 行強調時、行背景色 */
}
.syntaxhighlighter .line.highlighted.number {
  color: white !important; /* 行強調時、数字? */
}
.syntaxhighlighter .gutter .line.highlighted {
  background-color: #3185b9 !important; /* 行強調時、行番号背景色 */
  color: #121212 !important; /* 行強調時、行番号数字色 */
}
</style>

<b:if>

 なお、「class="brush:[言語]"」の部分は以下の言語に対応しているそうです。
「actionscript3」「as3」/「bash」「shell」/「coldfusion」「cf」/
「cpp」「c」/「c#」「c-sharp」「csharp」/「css」/
「delphi」「pascal」「pas」/「diff」「patch」/「erlang」「erl」/
「groovy」/「html」「xml」「xhtml」「xslt」/「java」/
「javafx」「jfx」/「javascript」「js」「jscript」/「perl」「pl」/
「php」/「text」「plain」/「powershell」「ps」/
「python」「py」/「ruby」「rails」「ror」/「scala」/
「sql」/「vb」「vbnet」

 懸念としては、新たな .js ファイルを読み込むので少し遅く(ソースコード掲載記事じゃなくても)なりそうですが、.js のファイルサイズが小さいので、相手側サーバーの応答が悪くなければ問題にはならない気がします。 一応、投稿記事内に<pre>タグがあれば SyntaxHighlighter を動的に読み込む方法もあるらしいので、そのうち検討してみます。

前後記事へのページネーションを修正

 これまでは掲載記事の下に「< 新しい投稿」「以前の投稿 >」と文字でリンクを表示していたけど、そっけないし視認性が良くない。 そこで、コンテナを囲んで視認性を良くし、リンク文字も記事タイトルにすることで『何を読むのか』を判る様にしました。
新しい前後記事へのページネーション
新しい前後記事へのページネーション
 ただし、この仕様だと前後の記事にもアクセスしちゃうので、表示が遅くなる懸念があります。 そこで、HTMLのレンダリング中は非表示にしてレンダリング最終で表示する様にしました。 なお、タイトル抽出・設定のスクリプトは こたつめがね さんのスクリプトを使わせて頂きました。 下記コードを</body>の上あたりに入れます。

ーマに追加したコード(</body> の上)
<!-- 前後記事のページネーション用タイトル抽出 -->
<b:if cond='data:view.isPost'>
<script type='text/javascript'>
//<![CDATA[
document.addEventListener('DOMContentLoaded',setPagerLinkTitleName);
function setPagerLinkTitleName(){
  setPageTitle('Blog1_blog-pager-older-link');
  setPageTitle('Blog1_blog-pager-newer-link');
}
function setPageTitle(objname){
  let obj=document.getElementById(objname);
  if(!obj) return;
  let link=obj.getAttribute('href');
  const page_path=link.split(location.hostname)[1];
  let feedUrl='/feeds/posts/summary?alt=json&path='+page_path+'&max-results=1';
  fetch(feedUrl)
  .then(response=>response.json())
  .then(json=>{
//	if(json.feed.entry&&json.feed.entry.length>0) obj.textContent=json.feed.entry[0].title.$t;obj.setAttribute('title',json.feed.entry[0].title.$t);
	if(json.feed.entry&&json.feed.entry.length>0) obj.textContent=json.feed.entry[0].title.$t; // title(吹き出し)は変えない
  })
  .catch(error=>console.log(error));
}
//]]>
</script>
</b:if>

<!-- 前後記事のページネーションを表示に設定する -->
<script type='text/javascript'>
//<![CDATA[
window.addEventListener('load', function() {
    var pPosts = document.getElementById('blog-pager');
    if (pPosts) {
        pPosts.style.display = 'block'; // 表示する
    }
}, false);
//]]>
</script>

</body>
 こたつめがねさんのスクリプトでは要素のtitle(blog-pager-newer-link.titleとか)も変更しちゃうので、吹き出しも投稿タイトルになっちゃうので、吹き出し文言は変えない様にしてあります。

ーマ追加したCSS(<head> の <b:skin> 内)
/*--------------------------------
   前後記事のページネーション用CSS
--------------------------------*/
#blog-pager {
    display: none;	/* 重いので最初は隠す */
}
.home-link {
  display: none;
}
#blog-pager-older-link {
  height: 40px;
  padding: 5px 0px;
  width: 48%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: right;
  /* 右側に尖った矢印を作る */
  clip-path: polygon(0% 0%, 97% 0%, 100% 50%, 97% 100%, 0% 100%, 3% 50%);
}
#blog-pager-newer-link {
  height: 40px;
  padding: 5px 0px;
  width: 48%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: left;
  /* 左側に尖った矢印を作る */
  clip-path: polygon(0% 50%, 3% 0%, 100% 0%, 97% 50%, 100% 100%, 3% 100%);
}

#blog-pager a {
  font-size: 1em;
  padding:16px 16px;
  box-sizing:border-box;
  text-decoration:none;
  color: #222222; 
  background-color: #90DD90;
  display: inline-block;
  transition:0.3s;
  width: 100%;
  border:none;
}
#blog-pager a:hover {
  text-decoration:none;
  color:#ffffff;
  background:#008ec2;
}
 最初に記述しているのはページネーション要素を非表示にする記述で、それ以下は矢印風の囲みや配色と動作を記述しています。 先に追加したコードが実効されることで要素が非表示から表示に変化します。

外部スクリプト読込みの見直し

 この Blogger用テーマも増築し続けたので、.xml コード全体を見直してみた。 すると、前後ページネーション用の id とトップページの記事一覧用ページネーション用 id とがバッティングしていた。💦 表示されるページが異なるので問題なく動作していたけど、cssで片方の色味を変更すると連動して変わっちゃうので気が付きました。 今はid名称を変更してあります。

jqueryの読み込み

 他から導入したコードをコピペしているので、複数個所で jquery を読み込んでいた。 しかも異なるバージョンで。💦 jquery は<head>部分で google の jquery を読込み済みなので、余計なjquery読込みをコメントアウトして少しは高速化を図りました。
 使用する jquery は https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js にしてみました。 これは、画像拡大表示用の FancyBox との整合性の兼ね合いです。 なお、<head>部分で読込む google の jquery は async や defer にすると各種スクリプトが機能不全を起こすので、async や defer にはしていません。
 外部スクリプトは async 設定にしたいところだけど、機能しなくなる場合もあるので、試してみて判断するしかありません。 なお、AdSense用の各 .js には全て async を付けて非同期読込みとしてあります。

htmlタグの検討→NG

 先頭の<html>タグに指示を追加することで、標準js や 標準css の読み込みをスキップする事が出来るらしい。 記述方法は以下の通りです。

<html b:css='false' b:js='false' b:version='2' class='v2' expr:dir='data:blog.languageDirection' lang='ja' 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'>

 b:js='false' とか記述すれば良いのだけど、残念ながら 標準js も 標準css も読込まない様にしたら機能不全・表示崩れが発生してどうしようもない。 軽量級のテーマなら有効そうだけど、各種機能を使って重めのテーマでは 標準js も 標準css も読込むしかなさそうです。

処理が重そうなパーツを非表示にする

 非表示にしたら見えなくなっちゃいますが、処理が重いパーツを最初は非表示に設定し、DOMのツリー構造が完了したら表示する様にしてみました。 他ページの内容を取得・チェックする以下のパーツに設定してあります。
  • 新前後記事のページネーション
    →大抵、最初は画面内にないから非表示で良い
  • 関連記事の表示
    →大抵、最初は画面内にないから非表示で良い
  • 人気記事一覧
    →最初から画面内の場合もあるけど、スマホ画面では下の方にある
<b:skin>のCSS内で非表示に設定しておき、</body>上部のスクリプトで表示に設定される様にしています。

●テーマに追加したCSS(<head> の <b:skin> 内)
<b:skin><![CDATA[
 :
#blog-pager {
    display: none;
}
#PopularPosts1 {
    display: none;
}
#related-posts {
  display: none;
}
 :
]]></b:skin>

●テーマに追加したコード(</body> の上)
<!-- DOMのツリー構造が完了したら表示に設定する -->
<script type='text/javascript'>
//<![CDATA[
window.addEventListener('DOMContentLoaded', function() {
    // 前後記事のページネーションを表示に設定する
    var pPosts = document.getElementById('blog-pager');
    if (pPosts) {
        pPosts.style.display = 'block'; // 表示する
    }
    // 人気記事一覧を表示に設定する
    var pPosts = document.getElementById('PopularPosts1');
    if (pPosts) {
        pPosts.style.display = 'block'; // 表示する
    }
    // 関連記事一覧を表示に設定する
    var pPosts = document.getElementById('related-posts');
    if (pPosts) {
        pPosts.style.display = 'block'; // 表示する
    }
}, false);
//]]>
</script>

 ちなみに、window.addEventListener('load', function() {処理させたいこと;})と書きたくなるのですが、これはDOMのレンダリングやCSS・画像などの関連リソースをすべて読み込んだ後に実行されるので、『バグったかな?』と思うほど遅くなります。 通常はDOMのツリー構造が完了したら、非表示を解除してパーツを動作させれば良いと思います。

画像のwebp化

Bloggerの設定画面の「WebP 画像の提供」と「画像の遅延読み込み」
Bloggerの設定画面
 2023年からBloggerの画像配信を自動的にwebp化して配信する機能が備わっていて、Bloggerの設定画面で「WebP 画像の提供」と「画像の遅延読み込み」をオンにすれば、手を加えることなくjpeg画像やpng画像などがwebp化して配信され、遅延読込みまでされる様になっていました。
 ただし、<a href="~~"></a>でリンクに記載している本画像のURLなどはwebp化されるURLて配信されないので、記事作成時に本画像のURLに「-rw」を付けて、強制的にwebp化配信させていました。 実際に動作を調べてみると、本画像へのリンクは通常のjpeg画像URLで、FancyBoxなどで拡大表示する画像はjpegのまま送られる来ます。 拡大画像はブログの初期描画速度には関係しないけど、拡大表示する場合は容量が大きな画像が送信されてしまうので、面倒だけど手動で「-rw」を追記してwebp化してやらない遅くなってしまいます。
 ちなみに、Bloggerの標準画像キャッシュ寿命は1日だけど、Bloggerの設定画面には画像のキャッシュ寿命設定などはありません。 裏技的に画像のURLに「-e30」を付ければ30日間のキャッシュ寿命となります。 頻繁に変更しない投稿内画像などなら「-rw」を手動で付加する際に「-e7-rw」とかににすればwebp化してキャッシュ寿命を7日間に伸ばせます。

<a href="https://blogger.googleusercontent.com/画像URL/s1600-e7-rw/S9A07411_top.jpeg" style="margin-left: auto; margin-right: auto;"><img alt="ALT文言" border="0" data-original-height="1067" data-original-width="1600" height="426" src="https://blogger.googleusercontent.com/画像URL/w640-h426-e7-rw/S9A07411_top.jpeg" title="TITLE文言" width="640" /></a>

 悩ましいのは、過去に投稿したサイズが大きな本画像のURLに、それぞれ「-e7-rw」などを付ける必要があり、とてつもなく作業が面倒です。

 なお、このままでは記事のトップ画像も遅延読込みの対象になってしまうので、記事のトップ画像は遅延読込みさせずに最優先で表示した方が良いでしょう。 そこで、記事投稿時にHTMLビューに切り替えて、トップ画像の <img> タグ内に fetchpriority="high"loading="eager" を付加して優先読込みに設定しています。 ちょっと面倒ですが、記事作成時に気が付いたら記述しておく程度で良いでしょう。

 ちなみに、Googleののブログの先頭でアクセス毎に表示がランダムに変化する画像は、サーバーの応答が少しでも速くなる様にwebp化した画像に差し替えてあります。

通信量を抑えて高速化

 これまでは高速化しようと思っていたけど、放置したままテーマを増築していたので、各所に無駄な部分が多々ありました。 特に画像の送信に関しては表示に必要なサイズ以上に大きな画像を端末に送ってから、端末側でリサイズする様な動作でした。 これを見直してサーバーから必要なサイズの画像を端末へ送る様に修正しました。

トップページのサムネイル画像サイズ

 特にトップページの記事一覧では、各記事の大きな先頭画像を端末に送り、端末でサムネイルサイズにリサイズしていたので、効率が悪すぎました。 修正の具体策は resizeImage 関数を使ってリサイズ済みのURLを生成し、サムネイルサイズの画像をサーバーから受け取る様に修正しました。
  変更前: <img expr:src='data:post.firstImageUrl'/>
  変更後: <img expr:src='resizeImage(data:post.firstImageUrl, 150)'/>
これによりトップページ(記事一覧ページ)の画像データの送信量が劇的に少なくなりました。 webp化はされませんが、サイズが小さいのでwebp化させるメリットは少ないでしょう。

関連記事のサムネイル画像サイズ

 次に関連記事のサムネイルも表示するサイズで送った方が良いけど、外部スクリプトの中で処理されているので、手を出しにくい。 Vaster2標準の関連記事表示機能の外部.jsファイルを覗いてみると、大きなサイズのままのURLを吐いているので、サイズ指定されたURLに差し換えるスクリプトを追加して、本テーマ内に埋め込みました。 ついでなので『alt文言が無い』と怒られる対策も施しておきました。 なお、今回の修正では私が良く使う画像サイズ(/s640/など)だけに対応したので、全ての元画像サイズには対応出来ていないのがイマイチです。

モバイル端末向けの最適化

 Google Analytics によると、本ブログに対するアクセスの50%ほどはモバイル端末でした。 PC表示なら良いとして、モバイル端末だと見易いとは言えないかもしれません。 そこで、一念発起してモバイル端末でも快適で見易い様に改善する事にしました。

モバイルテーマもデスクトップにしている
モバイルもデスクトップ
 実は、本テーマの中では data:blog.isMobile をチェックしていなくて、メディアクエリ(@media)を使って端末の表示横幅が768ピクセル以下ならモバイル向けのパーツサイズ設定やヘッダメニューをモバイル向けに折り畳む処理などを行っていました。 その理由はモバイル端末でもデスクトップと同じ表示イメージにしているためで、テーマ設定でモバイルの設定を「モバイル」にすれば data:blog.isMobile が有効になるけど、そっけない表示になってしまう。 これに手を加えるのが面倒だったのです。

広告のサイズ変更→モバイル画面の広告はオフにする

 モバイル端末で表示される広告が大きすぎて不快に感じる人も多いと思います。 そこで、モバイルサイズ画面の場合は広告を小さなサイズにして表示する様にしました。 実は、トップページの記事一覧内では実施済みだったのですが、他の部分の広告は...ほったらかしでした。m(_ _)m
 実施する内容は広告表示制御部分をデスクトップ用とモバイル用とに別け、それぞれに Class を設定しておきます。 後は <b:skin>内でデスクトップかモバイルかで表示する広告のオンオフを変更します。 実は、モバイル画面には小型広告にしようと思ったのですが、状態がなかなか反映されないのでイライラして非表示にしてしまいました。
 結局、モバイルサイズ画面では固定広告を殆どオフにしてありますが、広告表示収入なんて微々たるものなので、見易さ優先にしました。

自動広告を非表示にする→NG

 モバイルサイズ画面ではGoogleが挿入してくる自動広告が非常にうっとうしい。 自動広告のclassを指定して非表示にすれば良いのですが、古いclass情報(google-auto-placed)に従って実装してみても変化がありません。 Googleが挿入してくる自動広告の仕様が変わっているらしいのと、Googleのポリシー違反になる可能性があるので諦めました。

その他

 高速化とは関係ありませんが、本ブログの殆どの写真は私自身が撮影したものなので、ブログの最終に書作権を明示しました。

コメントを投稿

Sponsored Link