BloggerブログでIntersection Observerの画像の遅延読み込みをかけるカスタマイズ 結城永人 - 2019年4月17日 (水) サイトの表示速度を上げるために画面に入らなくてまだ表示される必要のない画像を画面に入って表示される段階で初めてブラウザに読み込ませるという画像の遅延読み込みの方法がある。 個人的に訪問者だけではなくて検索エンジンにも画像が把握できて検索結果へのサイト評価のSEO対策(検索できる最適化)にも有効と考えられるGooglも推奨するJavaScriptのIntersection Observerを使ったサイト作成を気に入ってブログに実装している。 追記:サイトの画像の遅延読み込みはHTMLのloading属性で簡単に行えるようになった。JavaScriptのIntersection observerも同じように使えるけど、サイトのプログラムで望み通りに動作させる以外の目的ではHTMLよりもコードを増やしてしまうので、むしろ画像以外のコンテンツの遅延読み込みやその他の無限スクロールなどの動作に使う方が向いているだろう。 Bloggerでのカスタマイズはどのように可能かを取り上げてみたい Lots of packed blueberries by elizadean / Pixabay 手順は二つあって特に2017年の公式テーマのContentsとSohoとEmporioとNotableのインデックスページのサムネイル画像――ページ毎に何枚も表示されるので、表示速度への遅延読み込みの効果が最も期待される――はテンプレートの当該のソースコードをプログラムに合わせて分解しなくてはならないから普通よりも手間がかかる。 スクリプトやライブラリーの導入(全サイト共通)テンプレートのソースコードの変更(Blogger向け) 事前の注意点としてJavaScriptのIntersection Observerの画像の遅延読み込みは対象の画像を非表示にしておいてJavaScriptのプログラムで表示に切り替える方法なんだ。だからブラウザのJavaScriptの機能がオフだとブログの対象の画像が非表示のままになってしまうのを考慮するべきだろう。どんな場合でも対象の画像を必ず表示する場合には画像の遅延読み込みのカスタマイズの他にnoscriptタグの<noscript></noscript>で従来のソースコードを囲って削除せずに載せておくと大丈夫だ。 先ずはJavaScriptのスクリプトかまたはライブラリーを使うならばスクリプトと共に外部ファイルを参照するためのタグもテンプレートのソースコードに追加しなくてはならない。 BloggerのテーマのHTML編集かバックアップ/復元からソースコードを変更する。 画像の遅延読み込みのJavaScriptプログラムは自作するか、無料で使えるのを挙げるとJeremy WagnerとRachel Andrewのスクリプト(公開元のweb.devのページ)やApoorv Saxenaのライブラリーのlazad.js(公開元のGitHubのページ)などが良いと思う。 スクリプトはブログのソースコードのbodyの閉じタグの</body>の上、ライブラリーもあればスクリプトに加えてブログのソースコードのheadの閉じタグの</head>上に記載する。 <html> <head> 中略 <script src='画像の遅延読み込みのライブラリーのURL'></script> </head> <body> 中略 <script> 画像の遅延読み込みのスクリプトのソースコード </script> </body> </html> ※scriptタグの配置はheadやbodyの閉じタグの真上でなくても構わない。 次いで画像のimgタグを編集しなくてはならない。プログラムによって違うかも知れないけれども一般的にclassを付けて画像URLの属性をsrcからdata-srcへ、レスポンシブの画面幅で幾つかを振り分けるsrcsetもあればdata-srcsetへ書き換える。例の二つのスクリプトやライブラリーでも同じだ。 <img class='遅延読み込み用のクラス名' data-src='画像URL' data-srcset-='小さな画像URL 狭い横幅, 大きな画像URL 広い横幅'/> ※画像のimgタグのsrcset属性の値は二種類以上の場合もあり得る。 Bloggerの公式テーマのデフォルトで画像にsrcsetが使われるのは新テーマのContempoとSohoとEmporioとNotableのスニペットのサムネイル画像の場合だ。注目とブログと人気の投稿の三つのウィジェットで全部か一部に適用されているので、必要なかぎりはサムネイル画像を表示するsrcと同様に接頭辞の「data」を新たに付ける。忘れるとサムネイル画像の縦横のバランスが崩れてしまうので、注意しなくてはならない。 imgタグの編集は記事/追加ページの通常の画像についてはそれぞれのHTML投稿から可能になる。その他のスニペットのサムネイル画像などのウィジェットから表示されるものについてはテーマのHTML編集かバックアップ/復元からソースコードを変更する必要がある。 スニペットのサムネイル画像はテーマ毎、そしてウィジェット毎にも画像の遅延読み込みのカスタマイズのimgタグかまたは特殊だけれどもデザインのCSSの背景画像のためのソースコードの編集が異なるので、個別に取り上げなくてはならない。 新テーマのContempoとSohoの注目とブログと人気の投稿ウィジェットとEmporioの人気の投稿ウィジェットとNotableの注目の投稿ウィジェットはテンプレートのソースコードにスニペットのサムネイル画像のimgタグがデフォルトで記載されてないので、独自タグを分解して取り出さなくてはならない。そしてEmporioのブログの投稿ウィジェットとNotableのブログと人気の投稿ウィジェットのスニペットのサムネイル画像はimgタグではなくて背景画像のbackground-image属性から表示されているので、又別のカスタマイズが求められる。 何れのテンプレートでも注目の投稿ウィジェットはブログの上段に表示されて画像の遅延読み込みは基本的に不要だと考える。ファーストビューならばむしろ反対に最速で表示されるべきコンテンツでではないか。新テーマのスニペットのサムネイル画像の遅延読み込みについては注目の投稿ウィジェットを除いてブログと人気の投稿ウィジェットをカスタマイズの対象に取り上げる。 Contempoテーマのスニペットのサムネイル画像Sohoテーマのスニペットのサムネイル画像Emporioテーマのスニペットのサムネイル画像Notableテーマのスニペットサムネイル画像 旧テーマのシンプルと動的ビューと画像ウィンドウとAwesome Inc.とウォーターマークとエスィリアルと旅行はテンプレートのソースコードにスニペットのサムネイル画像のimgタグがデフォルトで記載されているので、どこにあるかが分かれば直ちに相応しく書き換えられる。カスタマイズを求めるウィジェット毎、注目とブログと人気の投稿の三つのソースコードを個別に取り上げる。 旧テーマのスニペットのサムネイル画像 Bloggerのスニペットのサムネイル画像のimgタグの書き換えは新テーマで特に手間がかかるけど、しかし旧テーマを含めてウィジェット毎に行うために画像の遅延読み込みが全てに一括して反映するようになるから結果的に便利だともいえる。 Contempoテーマのスニペットのサムネイル画像 ブログの投稿ウィジェットのimgタグの編集 body内のBlogのtypeのwidget内のソースコードを書き換える。 デフォルトのソースコード <b:includable id='postBodySnippet' var='post'> <div class='container post-body entry-content' expr:id='"post-snippet-" + data:post.id'> <b:if cond='data:post.featuredImage'> <div class='snippet-thumbnail'> <b:include data='{ image: data:post.featuredImage, imageSizes: [32, 64, 128, 256], imageRatio: "1:1", sourceSizes: "(max-width: 800px) 20vw, 128px" }' name='responsiveImage'/> </div> </b:if> <b:include cond='data:post' data='post' name='postSnippet'/> </div> </b:includable> 斜体のresponsiveImageのidのincludable内の一部を変更する。 imgタグを取り出した場合 <b:includable id='postBodySnippet' var='post'> <div class='container post-body entry-content' expr:id='"post-snippet-" + data:post.id'> <b:if cond='data:post.featuredImage'> <div class='snippet-thumbnail'> <img class='遅延読み込み用のクラス名' expr:alt='data:messages.image' expr:data-src='data:post.featuredImage' expr:data-srcset='sourceSet('sourceSet(data:post.featuredImage, [32, 64, 128, 256], "1:1")' sizes='(max-width: 800px) 20vw, 128px'/> </div> </b:if> <b:include cond='data:post' data='post' name='postSnippet'/> </div> </b:includable> ブログのデザインを全く変えずにブログの投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性とsrcset属性に接頭辞のdataを追加している。 人気の投稿ウィジェットのimgタグの編集 body内のPopularPostsのtypeのwidget内のソースコードを書き換える。 必要なタグが記載されてないので、全て新しく記載する。 widget内にincldableタグを挿入するからwidget-settingsタグと他のincldableタグに入らないようにする。 imgタグを取り出したソースコード <b:includable id='snippetedPostThumbnail'> <div class='item-thumbnail'> <a expr:href='data:post.url'> <img class='遅延読み込み用のクラス名' expr:alt='data:messages.image' expr:data-src='data:post.featuredImage' expr:data-srcset='sourceset(data:post.featuredImage, [72,144], "1:1")' sizes='72px'/> </a> </div> </b:includable> ブログのデザインを全く変えずに人気の投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性とsrcset属性に接頭辞のdataを追加している。 Sohoテーマのスニペットのサムネイル画像 ブログの投稿ウィジェットのimgタグの編集 body内のBlogのtypeのwidget内のソースコードを書き換える。 デフォルトのソースコード <div class='post'> 中略 <b:if cond='data:post.featuredImage'> <div class='snippet-thumbnail'> <a expr:href='data:post.url'> <b:comment>Max width is 576, so max size @ 2x is 1152.</b:comment> <b:include data='{ image: data:post.featuredImage, imageSizes: [320,490,576,1152], sourceSizes: "(max-width: 576px) 100vw, (max-width: 1024px) 576px, 490px" }' name='responsiveImage'/> </a> <b:include name='headerByline'/> </div> <b:else/> <b:include name='headerByline'/> </b:if> 中略 </div> 斜体のresponsiveImageのidのincludable内の一部を変更する。 imgタグを取り出した場合 <div class='post'> 中略 <b:if cond='data:post.featuredImage'> <div class='snippet-thumbnail'> <a expr:href='data:post.url'> <b:comment>Max width is 576, so max size @ 2x is 1152.</b:comment> <img class='遅延読み込み用のクラス名' expr:alt='data:messages.image' expr:data-src=data:post.featuredImage' expr:data-srcset='sourceSet(data:post.featuredImage, [320,490,576,1152])' sizes='(max-width: 576px) 100vw, (max-width: 1024px) 576px, 490px'/> </a> <b:include name='headerByline'/> </div> <b:else/> <b:include name='headerByline'/> </b:if> 中略 </div> ブログのデザインを全く変えずにブログの投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性とsrcset属性に接頭辞のdataを追加している。 人気の投稿ウィジェットのimgタグの編集 body内のPopularPostsのtypeのwidget内のソースコードを書き換える。 デフォルトのソースコード <div class='post'> 中略 <b:if cond='data:post.featuredImage'> <div class='snippet-thumbnail'> <a expr:href='data:post.url'> <b:include data='{ image: data:post.featuredImage, imageSizes: [330,660,1320], sourceSizes: "(max-width: 660px) 100vw, 660px" }' name='responsiveImage'/> </a> <b:include name='headerByline'/> </div> <b:else/> <b:include name='headerByline'/> </b:if> 中略 </div> 斜体のresponsiveImageのidのincludable内の一部を変更する。 imgタグを取り出した場合 <div class='post'> 中略 <b:if cond='data:post.featuredImage'> <div class='snippet-thumbnail'> <a expr:href='data:post.url'> <img class='遅延読み込み用のクラス名' expr:alt='data:messages.image' expr:data-src='data:post.featuredImage' expr:data-srcset='sourceSet(data:post.featuredImage, [330,660,1320])' sizes='(max-width: 660px) 100vw, 660px'/> </a> <b:include name='headerByline'/> </div> <b:else/> <b:include name='headerByline'/> </b:if> 中略 </div> ブログのデザインを全く変えずに人気の投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性とsrcset属性に接頭辞のdataを追加している。 Emporioテーマのスニペットのサムネイル画像 ブログの投稿ウィジェットscriptタグの編集 他のテーマと違ってスニペットの画像がデザインのCSSのbackground-image属性で表示する背景画像の扱いになっている。ブログに取り入れるには画像の遅延読み込みのスクリプトの内容にも注意しなくてはならない。 JavaScriptのIntersection Observer APIで一般的に監視する要素と画像を後から表示する要素は同じだから所定のスクリプトのclassは変える必要はない。 しかしCSSの背景画像にかける場合は必要なclassの有無で遅延読み込みの対象を判別しなくてはならない。いい換えるとブラウザの画像の読み込みを、一旦、止めさせるためにどうするかで、通常の画像ではimgタグのsrc属性やsrcset属性に接頭辞のdataを付けて直ぐに表示させない代わりに背景画像ではCSSに対応するclassを前以て外しておく。そして監視する要素がサイトの画面に入って来たら初めて背景画像に対応するclassを付けて表示するようにマークアップを切り替える。 参考サイトCSS でのイメージ処理(イメージと動画の遅延読み込み) 画像の遅延読み込みのライブラリーを使う場合は背景画像にかぎらず、独自の方法が取られるかも知れないので、公開元の説明に従って貰うしかない。 スクリプトで監視する要素 div.snippet-thumbnail どのように監視する要素を取り込むかはプログラミングによって変わる。 Jeremy WagnerのスクリプトだとdocumentへのquerySelectorAllメソッドの引数に監視する要素の「div.snippet-thumbnail」が入るので、プログラミングではdocument.querySelectorAll("div.snippet-thumbnail");という書き方になる。 Apoorv Saxenaのライブラリーのlazad.jsだと背景画像を表示できる領域のdivタグなどの監視する要素にlozadのclassと背景画像URLのdata-background-imageを追加する。この場合は元々のCSSの背景画像があればstyle内の背景画像URLのbackground-imageか少なくともbody内の監視する要素の対応するclassを削除しないとブラウザの読み込みを止められないから注意するべきだ。サイトに新たに遅延読み込みの背景画像を追加する場合は通常の画像と基本的に変わらず、imgタグに特定の属性のdata-background-imageで画像URLを記載するだけだから簡単なんだ。 次いで監視する要素が画面に入ったら所定の 画像を送り込むために新しくクラス名を付けるプログラム(CSSに記載された画像へも対応するクラス名を新しく付けなくてはならない)も書き換える。 スクリプトでクラス名を追加するサンプル lazyImage.classList.add("遅延読み込み用のクラス名"); Jeremy Wagnerのスクリプトだと監視する要素に「lazyimage」の変数が付けられているので、クラス名を追加するclassListへのaddメソッドを使うと良いと思う。 プログラムによって変数は異なるにせよ、classList以下は同じで大丈夫だ。 スクリプトの「lazyImage.classList.remove("lazy");」(変数のlazyImageの監視する要素からlazyのクラス名を外す)などのデフォルトのHTMLの画像のためのプログラミングは削除して構わない。 ライブラリーを使う場合はscriptタグの編集は須く不要かも知れないし、lozad.jsだとマークアップのdata-background-image属性でのカスタマイズだから関係ないんだ、それぞれの説明通りに行う。 テンプレートのスニペットのサムネイル画像ための遅延読み込みのスクリプトの監視する要素を設定したらプログラムに必要なかぎりはマークアップにclassを追加する。 head内のCommonのtypeのdefaultmarkup内のソースコードを書き換える。 カスタマイズしたソースコード <b:includable id='standardPostImageStyle'> <b:with value='"post-thumb-" + data:post.id' var='thumbClassName'> <style> .<data:thumbClassName/>.遅延読み込み用のクラス名 {background-image:url(<b:eval expr='resizeImage(data:post.featuredImage, 385, "385:184").cssEscaped'/>);} </style> </b:with> </b:includable> ブログのデザインを全く変えずにブログの投稿ウィジェットのスニペットのサムネイル画像の背景画像URLに遅延読み込み用のclassを追加している。 改めて断っておくと背景画像の遅延読み込みはプログラミングによってカスタマイズの仕方が大きく変わり得る。取り分けライブラリーを使っている場合には固有のカスタマイズもあるかも知れないから見落とさないように注意しなくてはならない。 人気の投稿ウィジェットのimgタグの編集 body内のPopularPostsのtypeのwidget内のソースコードを書き換える。 デフォルトのソースコード <b:includable id='snippetedPostThumbnail'> <div class='item-thumbnail'> <a expr:href='data:post.url'> <b:include data='{ image: data:post.featuredImage, imageSizes: [280,560,840,1120,1400] }' name='responsiveImage'/> </a> </div> </b:includable> 斜体のresponsiveImageのidのincludable内の一部を変更する。 imgタグを取り出した場合 <b:includable id='snippetedPostThumbnail'> <div class='item-thumbnail'> <a expr:href='data:post.url'> <img class='遅延読み込み用のクラス名' expr:alt='data:messages.image' expr:data-src='data:post.featuredImage' expr:data-srcset='sourceset(data:post.featuredImage, [280,560,840,1120,1400], "1:1")'/> </a> </div> </b:includable> ブログのデザインを全く変えずに人気の投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性とsrcset属性に接頭辞のdataを追加している。 Emporioテーマはブログと人気の投稿の両方のウィジェットに画像の遅延読み込みを取り入れる際にはIntersection Observer APIを使うと監視する要素も二つに分かれるから調整しなくてはならない。 document.querySelectorAll("div.snippet-thumbnail", "img.lazy"); 一般的な仕方だと例えばquerySelectorAllメソッドなどで取り込む対象が複数ならば半角コンマ(,)で区切って併記するだけで、それぞれに動作するのがIntersection Observer APIなんだ。 ライブラリーを使う場合は監視する要素の取り込みの仕方が固有にあるかも知れないからそれぞれの説明通りに設定する。 Notableテーマのスニペットのサムネイル画像 ブログと人気の投稿の二つのウィジェットでサムネイル画像は共通して表示されるからカスタマイズも一回で両方とも反映される。 ただしHTMLのimgタグの通常の画像ではなくてデザインのCSSのbackground-image属性の背景画像が使われているので、カスタマイズの方法が一般的ではない。 ブログと人気の投稿ウィジェットのscriptタグの編集 NotableテーマもEmporioテーマのブログの投稿ウィジェットのサムネイル画像の場合と同様にIntersection Observer APIのスクリプトの変更が必要になって来る。 スクリプトで監視する要素 span.snippet-thumbnail-img スクリプトでクラス名を追加するサンプル lazyImage.classList.add("遅延読み込み用のクラス名"); JavaScriptのaddメソッドでクラス名を追加するspan.snippet-thumbnailの要素を取得した変数の「lazyImage」の部分はプログラムによって異なる。 サンプルはJeremy Wagnerのスクリプトの場合で、他のスクリプトを使う場合は相応しく書き換えなくてはならない。 ライブラリーを使う場合は固有の仕方があり得るので、例えばlozad.jsだとスクリプトの変更を完全に省略できたり、それぞれの説明通りに設定する。 一般的な仕方として背景画像の遅延読み込みのためにスクリプトを変更したらCSSのbackground-imageのクラス名も変更しなくてはならない。 head内のCommonのtypeのdefaultmarkup内のソースコードを書き換える。 カスタマイズしたソースコード <b:includable id='normalPost'> 中略 <style> @media (min-width: 1168px) { <b:eval expr='"#snippet_thumbnail_id_" + data:post.id'/>.遅延読み込み用のクラス名 { background-image: url(<b:eval expr='resizeImage(data:post.featuredImage, 256, "1:1").cssEscaped'/>); } } @media (min-width: 969px) and (max-width: 1167px) { <b:eval expr='"#snippet_thumbnail_id_" + data:post.id'/>.遅延読み込み用のクラス名 { background-image: url(<b:eval expr='resizeImage(data:post.featuredImage, 1167, "3:2").cssEscaped'/>); } } @media (min-width: 601px) and (max-width: 968px) { <b:eval expr='"#snippet_thumbnail_id_" + data:post.id'/>.遅延読み込み用のクラス名 { background-image: url(<b:eval expr='resizeImage(data:post.featuredImage, 968, "3:2").cssEscaped'/>); } } @media (max-width: 600px) { <b:eval expr='"#snippet_thumbnail_id_" + data:post.id'/>.遅延読み込み用のクラス名 { background-image: url(<b:eval expr='resizeImage(data:post.featuredImage, 600, "3:2").cssEscaped'/>); } } </style> 中略 </includable> ブログのデザインを全く変えずにブログと人気の投稿ウィジェットのスニペットのサムネイル画像の背景画像URLに遅延読み込み用のclassを追加している。 もしもブログと人気の投稿の二つのウィジェットを振り分けて画像の遅延読み込みをかけたい場合はBloggerの独自タグを使って背景画像のCSSを編集するだけで大丈夫だ。 ブログの投稿ウィジェットへの書き換え <b:includable id='normalPost'> 中略 <b:if cond='!data:this.postDisplay.showFeaturedImage'> <style> 遅延読み込み用のクラス名を付けたbackground-imageのCSS </style> <b:else/> <style> デフォルト(遅延読み込み用のクラス名なし)のbackground-imageのCSS </style> 中略 </b:if> 人気の投稿ウィジェットへの書き換え ブログの投稿ウィジェットへの切り替えの「!data:this.postDisplay.showFeaturedImage!」から半角エクスラメーション(!)を外して「data:this.postDisplay.showFeaturedImage」にして他は同じに記載する。 どちらも背景画像の何れも条件分岐の独自タグのifのcondの条件から切り替えながら背景画像のCSSのソースコードに遅延読み込み用のクラス名を個別にevalで記載している。 旧テーマのスニペットのサムネイル画像 注目の投稿ウィジェットのimgタグの編集 body内のFeaturedPostのtypeのwidget内のソースコードを書き換える。 カスタマイズしたソースコード <b:includable id='content'> 中略 <b:if cond='data:showFirstImage and data:postFirstImage != ""'> <img class='image 遅延読み込み用のクラス名' expr:data-src='data:postFirstImage'/> </b:if> 中略 </b:includable> 太字のcontentのidのincludable内の一部を変更する。 ブログのデザインを全く変えずに注目の投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性に接頭辞のdataを追加している。 ブログの投稿ウィジェットのimgタグの編集 サムネイル画像はスマホ/モバイルでしか使われない。 旧テーマのパソコン/デスクトップのインデックスページにデフォルトで表示されるのは通常画像で、投稿したものがそのままに使われている。もしも画像の遅延読み込みを取り入れるならば個別ページの投稿画像として個々にimgタグを編集しなくてはならない。 スマホ/モバイルにかぎってサムネイル画像のカスタマイズが可能になる。 body内のBlogのtypeのwidget内のソースコードを書き換える。 カスタマイズしたソースコード <b:includable id='mobile-index-post' var='post'> 中略 <b:if cond='data:post.thumbnailUrl'> <div class='mobile-index-thumbnail'> <div class='Image'> <img class='遅延読み込み用のクラス名' expr:data-src='data:post.thumbnailUrl'/> </div> </div> </b:if> 中略 </b:includable> 太字のmobile-index-postのidのincludable内の一部を変更する。 ブログのデザインを全く変えずにブログのスマホ/モバイルバージョンのブログの投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性に接頭辞のdataを追加している。 人気の投稿ウィジェットのimgタグの編集 body内のPopularPostsのtypeのwidget内のソースコードを書き換える。 カスタマイズしたソースコード <b:includable id='main'> 中略 <b:if cond='data:post.featuredImage.isResizable or data:post.thumbnail'> <div class='item-thumbnail'> <a expr:href='data:post.href' target='_blank'> <b:with value='data:post.featuredImage.isResizable ? resizeImage(data:post.featuredImage, 72, "1:1") : data:post.thumbnail' var='image'> <img class='遅延読み込み用のクラス名' alt='' border='0' expr:data-src='data:image'/> </b:with> </a> </div> </b:if> 中略 </b:includable> 太字のmainのidのincludable内の一部を変更する。 ブログのデザインを全く変えずに人気の投稿ウィジェットのスニペットのサムネイル画像のimgタグに遅延読み込み用のclassやsrc属性に接頭辞のdataを追加している。 コメント 新しい投稿 前の投稿
コメント