記事/追加ページの画像の遅延読み込みや軽量化による高速化のカスタマイズ 結城永人 -3月 11, 2022 ブログに画像や動画を掲載すると容量が大きくてページの表示速度が下がります。閲覧するのに時間が訪問者を減るかも知れないので、なるべくページの表示速度を高めた方が良いと思います。 初回画面が三秒以内に表示されれば遅くて嫌になることは少ないといわれます。 魅力的な画像や動画を掲載しても不利益を被らないために記事/追加ページの高速化として投稿画像や動画の遅延読み込みや軽量化などのカスタマイズを紹介します。 Imaginaryに高速化のプログラムを取り付ける Man tying his shoes by Alexander Redl / Unsplash 投稿画像や動画の遅延読み込みや軽量化などの高速化に関して有利だと考えられる様々な機能を一つに纏めたプログラムを使います。 普通よりも使い辛くなる部分がありますので、予め留意して取り付けるようにして下さい。 記事本文をJavaScriptを使って出します。Googleなどの検索エンジンが従来のHTMLだけの場合と全く同じようにブログを把握するとはかぎりません。アクセスが低下する場合があり得ますので、様子を見ながら使って良くなければ外して下さい。アドセンスの自動広告を使った場合、アドセンスの管理画面の広告の設定のプレビューが正常に機能しないようなので、そのときは一時的に外して下さい。CSSのdisplay:gridで二段(縦二列)以上の横並びを行うと大きな画像がはみ出す場合があり、親要素のgrid-template-columnsを「%」の単位で指定すると避けられます。同時にgapを使うと親要素の幅が広がりますので、計算式のcalc()でセルの大きさを均等に引いて下さい。例_grid-template-columns:calc(50 % - 0.5em) calc(50 % - 0.5em);gap:1em/二つのセルの横並びに1emの隙間を付ける その他、初期設定のままだと投稿画像をスマホ/タブレットで640px、パソコンで1024pxの横幅で出します。使いたい画像のサイズが合わない場合はプログラムのレスポンシブ配信を編集して下さい。 Bloggerの管理画面のテーマのメニュー(▼)のHTMLを編集かバックアップと元に戻すでテンプレートのソースコードを書き換えます。 body内の一ヵ所を編集します。 投稿画像と動画の遅延読み込みと軽量化など 書き換え前のソースコード:Blog1ウィジェット <b:includable id='postBody' var='post'> <!-- If metaDescription is empty, use the post body as the schema.org description too, for G+/FB snippeting. --> <div class='post-body entry-content' expr:id='"post-body-" + data:post.id'> <data:post.body/> </div> </b:includable> 書き換え後のソースコード:Blog1ウィジェット <b:includable id='postBody' var='post'> <!-- If metaDescription is empty, use the post body as the schema.org description too, for G+/FB snippeting. --> <div class='post-body entry-content' expr:id='"post-body-" + data:post.id'> <b:tag class='blog-content' cond='data:view.featuredImage' name='noscript'><data:post.body/></b:tag> </div> <b:if cond='data:view.featuredImage'> <script>/* Loading, decording and parameters*/ const psbd = Blog1.querySelector("div.post-body"), blct = psbd.querySelector("noscript.blog-content"), npsbd = psbd.cloneNode(false), nl = document.createElement("div"); nl.style.height = "100vh"; psbd.insertBefore(nl, blct); npsbd.insertAdjacentHTML("afterbegin", blct.innerText); const blimgs = npsbd.querySelectorAll("img, iframe"); Promise.all([...blimgs].map(blimg => { const bisrc = blimg.src, aroi = blimg.dataset.originalWidth / blimg.dataset.originalHeight, sssw = aroi < 1 ? Math.trunc(640 / aroi) : 640, lssw = aroi < 1 ? Math.trunc(1280 / aroi) : 1280; if (/blogger\.googleusercontent\.com\/img\/a\//.test(bisrc)) { blimg.dataset.src = /=.*$/.test(bisrc) ? bisrc + "-rw-e100" : bisrc + "=rw-e100"; const wogp = /^.+=/.exec(blimg.dataset.src); blimg.dataset.srcset = wogp[0] + "w" + sssw + "-rw-e100 " + sssw + "w, " + wogp[0] + "w" + lssw + "-rw-e100 " + lssw + "w"; } else { if (/\.(jpg|jpeg)/i.test(bisrc)) { const pmoi = /^(.+\/)(.*)(\/.*)$/.exec(bisrc); blimg.dataset.src = pmoi[1] + pmoi[2] + "-rw-e100" + pmoi[3]; } else { blimg.dataset.src = bisrc; } if (blimg.tagName === "IMG") { const rwpm = /\.(jpg|jpeg)/i.test(bisrc) ? "-rw" : "", wobp = /^(.+\/)(.*)(\/.*)$/.exec(blimg.dataset.src); blimg.dataset.srcset = wobp[1] + "w" + sssw + rwpm + "-e100" + wobp[3] + " " + sssw + "w, " + wobp[1] + "w" + lssw + rwpm + "-e100" + wobp[3] + " " + lssw + "w"; }} if (blimg.height) { if (!blimg.width && aroi) blimg.width = blimg.height * aroi; } else if (blimg.width) { if (aroi) blimg.height = blimg.width / aroi; } else if (aroi && !blimg.style.aspectRatio) { blimg.style.aspectRatio = aroi; blimg.height = blimg.dataset.originalHeight; blimg.width = blimg.dataset.originalWidth; } blimg.src = ""; return blimg; })).then(results => { psbd.parentNode.replaceChild(npsbd, psbd); const postContentObserver = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { const et = entry.target; if (et.tagName === "IMG" && entry.boundingClientRect.top < window.innerHeight) et.decoding = "async"; if (et.dataset.srcset) { et.srcset = et.dataset.srcset; delete et.dataset.srcset; } et.src = et.dataset.src; delete et.dataset.src; postContentObserver.unobserve(et); }}); }, { rootMargin: "240px" }); results.forEach(result => { if ("IntersectionObserver" in window) postContentObserver.observe(result); else result.src = result.dataset.src; }); }); const pbscs = npsbd.querySelectorAll("script"); if (pbscs) { pbscs.forEach(pbsc => { const npbsc = document.createElement("script"); if (pbsc.src) npbsc.src = pbsc.src; if (pbsc.async) npbsc.async = "async"; if (pbsc.textContent) npbsc.textContent = pbsc.textContent; npsbd.appendChild(npbsc); }); } const pbscs = npsbd.querySelectorAll("script"); if (pbscs) { pbscs.forEach(pbsc => { const npbsc = document.createElement("script"); if (pbsc.src) npbsc.src = pbsc.src; if (pbsc.async) npbsc.async = "async"; if (pbsc.textContent) npbsc.textContent = pbsc.textContent; npsbd.appendChild(npbsc); }); }</script></b:if> </b:includable> テンプレートのBlog1ウィジェット内のpostBodyのidのincludableタグの、そのまま、取り替えて保存すると作業は完了します。 注意:Imaginary以外のテンプレートで無断使用しないで下さい。プログラムは著作物です。少なくとも作者名(結城永人)とソースコードの出典が必要です。Imaginaryには同じ作者名とテンプレートの出典が含まれるために個別のカスタマイズに関して省略を許可します。 その他のテンプレートで記事/追加ページの投稿画像の高速化の同プログラムを使いたい場合は/* Copyright: Nagahito Yuki 2022 | https://imaginary-theme.blogspot.com/2022/03/customization-for-pagespeed-of-post-and-added-page.html | License: The MIT License */という著作権とライセンスの表記をプログラムの冒頭などに追加して下さい。 遅延読み込みの動作確認用プログラム プログラムの動作は目に見えるものではありませんので、ブログにちゃんと組み込めたかどうかは動作確認用プログラムで調べて下さい。 results.forEach(result => { result.onload = () => { alert((result.tagName === 'IMG' ? '画像' : '動画') + "の読み込みが完了しました\u3002\ndecoding属性は\u300c" + result.getAttribute("decoding") + "\u300dの状態です\u3002"); } if ("IntersectionObserver" in window) postContentObserver.observe(result); else result.src = result.dataset.src; }); 太字の部分を前後のソースコードの間に挿入します。記事/追加ページの画像や動画が読み込まれると完了のアラートが出ます。初回画面の画像や動画は記事/追加ページを開いて直ぐに出て画像外のものはスクロールで近付いたときに出れば成功です。 同時に初回画面の画像の優先読み込みのdecoding属性の状態も出ます。初回画面の画像が「async」(優先読み込み可能)で、遅延読み込みされたものが「null」(値なし)になっていれば成功です。 動作確認が終わったら忘れずに挿入した動作確認用プログラムを取り除いて下さい。 その他、記事/追加ページをサイトのパフォーマンスを調べるPageSpeed Insightsにかけても、ある程度、分かります。診断結果で「オフスクリーン画像の遅延読み込み」(画像の遅延読み込みの状態)や「次世代フォーマットでの画像の配信」(画像のWebPによる軽量化の状態)で合格しなかったら不具合がありますので、プログラムの取り付けをやり直して下さい。 Imaginaryに追加した高速化の機能と使い方 ブログを投稿画面から作成したとき、一般的に不具合がなく、最適な閲覧ができるような高速化のプログラムです。 画像と動画の遅延読み込み画像にサイズを付ける画像の優先読み込み画像のデータの軽量化画像のキャッシュ期限画像のレスポンシブ配信 画像と動画の遅延読み込み 初回画面に入らない画像と動画の読み込みを止めてブログの記事/追加ページの表示速度を速めます。画面が動画がない場合は変わりません。 遅延読み込みの対象 const blimgs = npsbd.querySelectorAll("img, iframe"); 遅延読み込みの対象はimgタグの画像とiframeタグの動画です。プログラムの("img, iframe")のHTML要素を書き換えると特定の画像や動画に絞ったり、その他のコンテンツに遅延読み込みを適用できます。 判定の余白 rootMargin: "240px" 画面外の画像や動画は画面に入るときに読み込まれて表示されますが、実際は判定の余白が付いていてもう少し早く読み込まれます。初期値は「240px」です。画面に入る瞬間よりも前に読み込みを開始した方が表示するまでの待ち時間を短縮できます。画面の下端よりもどのくらい前から読み込みを開始するか、元の「240px」の数値を変えると調整できます。 関連:Bloggerの投稿画像の自動的な遅延読み込みを確実に行うためのプログラム 画像にサイズを付ける Bloggerの投稿画像は取り込むサイズでHTMLのimgタグにheight(縦幅)かwidth(横幅)の属性が付くかオリジナルサイズのdata-original-height(縦幅)とdata-original-width(横幅)の属性が必ず付きます。 小と中と大と特大はheightかwidthのどちらか一つとオリジナルサイズの二つ、元のサイズはオリジナルサイズだけです。 ブラウザはimgタグのheight属性とwidth属性から縦横緋が分かると画像をもっと速やかに表示できるといわれるので、プログラムはオリジナルサイズの縦横を使って両方とも付けるようにしています。 動画に関してはYouTubeはBloggerの投稿画面から取り込むと自動的にheightとwidthの属性が付きます。その他の場合はHTMLビューで動画のiframeタグになるべく付けておく方が良いと思います。 関連:Bloggerの記事/追加ページの投稿画像にloading-lazyを自動的に付けるプログラム 画像の優先読み込み 初回画面に入る画像が早く表示できると待ち時間を減らすことができて快適なので、imgタグにdecoding属性のasyncを付けて優先読み込みを指定してます。 関連:画像のdecoding-async:非同期処理による高速化について 画像のデータの軽量化 Bloggerの画像は画像URLのパラメーターに「rw」を付けるとデータが軽量化されて高速表示に繋がるWebPのファイル形式に変更できので、取り入れてます。 JPG/JPEGファイルの画像からWebPファイルに変更するのが最も効果的で、三割程度、軽くなりますので、投稿で取り込むのはなるべくJPG/JPEGの画像にして下さい。GIFファイルは変わらず、PNGは逆に重くなる場合もあるので、ブログて使うときは注意して下らない。 不要な場合はソースコードを編集して下さい。 追記:2022年3月から新しい画像URLのパターンが変更されて古い画像URLと同じになりましたので、古い画像URLのソースコードを削除しないようにして下さい。 画像の軽量化のプログラムは二つの画像URLとそれぞれに元の画像とレスポンシブ画像の四つ場合に分かれてます。 2021年の夏頃からBloggerの投稿画像のURLが変わり始めました。新しいドメインが「blogger.googleusercontent.com」で、古いドメインが先頭に1から4までのどれかの数字が付いた「bp.blogspot.com」です。 新しい方は画像URLから画像ファイルの形式が分かりませんので、プログラムで軽量化をWebPの変更に有利なJPG/JPEGファイルの画像に限定することができません、古い方は画像ファイルが分かるので、JPG/JPEG以外のファイル形式の画像には軽量化を行いません。 そしてプログラムは画像のレスポンシブ配信を組み込んでいて実際にブログに表示するのは、殆どの場合、元の画像ではなく、スマホ/タブレットで小さめに、パソコンで大きめにサイズを変更したものになります。 新しい画像URLの元の画像 blimg.dataset.src = /=.*$/.test(bisrc) ? bisrc + "-rw-e100" : bisrc + "=rw-e100"; 一つ目のrwは画像を小か中か大か特大で取り込んだ場合(投稿のHTMLビューのカスタマイズで新しいパラメーターを付けたものも含む)、二つ目のrwは元のサイズで取り込んだ場合のものです。 新しい画像URLのレスポンシブ画像 blimg.dataset.srcset = wogp + "w640-rw-e100 640w, " + wogp + "w1024-rw-e100"; 一つ目のrwはスマホ/タブレットの小画面の表示用、二つ目のrwはパソコンの大画面の表示用のものです。 古い画像URLの元の画画 blimg.dataset.src = pmoi[1] + pmoi[2] + "-rw-e100" + pmoi[3]; 全てのJPG/JPEG画像のためのrwです。 古い画像URLのレスポンシブ画像 blimg.dataset.srcset = wobp[1] + "w640-rw-e100" + wobp[3] + " 640w, " + wobp[1] + "w1024-rw-e100" + wobp[3] + " 1024w"; 一つ目のrwはスマホ/タブレットの小画面のJPG/JPEG画像の表示用、二つ目のrwはパソコンの大画面のJPG/JPEG画像の表示用です。 ソースコードの「rw」のパラメーターを削除すると軽量化を行いません。編集するときはそれぞれに太字の部分を行います。前後の半角ハイフン(-)や半角イコール(=)を余計に消したり、無駄に残りしたりしないように注意して下さい。 関連:Bloggerの記事/追加ページの投稿画像にWebPのrwを自動的に付けるプログラム 画像のキャッシュ期限 Bloggerの画像URLにパラメーターの「e*」(*は数値)を付けるとブラウザが画像を二回目以降の閲覧で読み込まずに出すために保存するキャッシュ期限を設定できます。 初期値で「100」の百日のキャッシュ期限になってます。数値を変えることができますし、不要ならは削除して下さい。 プログラムの構成は軽量化のものと同じで、軽量化のパラメーターの「rw」の次にキャッシュ期限の「e100」が付いてます。 新しい画像URLの元の画像 blimg.dataset.src = /=.*$/.test(bisrc) ? bisrc + "-rw-e100" : bisrc + "=rw-e100"; 一つ目のe100は画像を小か中か大か特大で取り込んだ場合(投稿のHTMLビューのカスタマイズで新しいパラメーターを付けたものも含む)、二つ目のe100は元のサイズで取り込んだ場合のものです。 新しい画像URLのレスポンシブ画像 blimg.dataset.srcset = wogp + "w640-rw-e100 640w, " + wogp + "w1024-rw-e100"; 一つ目のe100はスマホ/タブレットの小画面の表示用、二つ目のe100はパソコンの大画面の表示用のものです。 古い画像URLの元の画画 blimg.dataset.src = pmoi[1] + pmoi[2] + "-rw-e100" + pmoi[3]; 全てのJPG/JPEG画像のためのe100です。 古い画像URLのレスポンシブ画像 blimg.dataset.srcset = wobp[1] + "w640-rw-e100" + wobp[3] + " 640w, " + wobp[1] + "w1024-rw-e100" + wobp[3] + " 1024w"; 一つ目のe100はスマホ/タブレットの小画面のJPG/JPEG画像の表示用、二つ目のe100はパソコンの大画面のJPG/JPEG画像の表示用です。 ソースコードの「e100」のパラメーターを削除するとキャッシュ期限を取りません。編集するときはそれぞれに太字の部分を行います。直前の半角ハイフン(-)や半角イコール(=)を余計に消したり、無駄に残りした ないように注意して下さい。 関連:Bloggerの記事/追加ページの投稿画像にWebPのrwを自動的に付けるプログラム 画像のレスポンシブ配信 ブログに実際に表示する画像はレスポンシブ配信で二種類に決められてます。すなわちデバイスの画面幅で振り分けたスマホ/タブレット用の小さなものとパソコン用の大きなものです。殆ど場合、どちらかの画像が表示されて元の画像は使われません。元の画像が使われるのは振り分けのimgタグのsrcset属性に対応してないか適用されないか、ブラウザによって反映しません。 二つのサイズの初期値は小さなものが横幅640px、大きなものが横幅1024pxになってます。プログラムの編集で変えたり、レスポンシブ配信を止めることができます。 スマホ用のレスポンシブ画像の横幅 sssw = aroi < 1 ? Math.trunc(640 / aroi) : 640 パソコン用のレスポンシブ画像の横幅 lssw = aroi < 1 ? Math.trunc(1280 / aroi) : 1280 スマホ用とパソコン用のどちらも二つずつある数値を変えるとレスポンシブ画像の横幅を変えることができます。 二つずつある数値の前の方は縦長の画像の横幅を算出します。 縦長の画像の場合は縦幅の初期値が640pxと1280pxになり、横幅は横長の画像の場合よりも短くなります。縦幅は反対に長くなりますから画像の全体的なサイズはどちらも同じです。 プログラムは二種類の画像URLに分かれてます。 追記:2022年3月から新しい画像URLのパターンが変更されて古い画像URLと同じになりましたので、プログラムの動作も古い画像URLと同じになります。 2021年の夏頃からBloggerの投稿画像のURLが変わり始めました。新しいドメインが「blogger.googleusercontent.com」で、古いドメインが先頭に1から4までのどれかの数字が付いた「bp.blogspot.com」です。 新しい画像URLのレスポンシブ画像 const wogp = /^.+=/.exec(blimg.dataset.src); blimg.dataset.srcset = wogp[0] + "w" + sssw + "-rw-e100 " + sssw + "w, " + wogp[0] + "w" + lssw + "-rw-e100 " + lssw + "w"; 古い画像URLのレスポンシブ画像 if (blimg.tagName === "IMG") { const rwpm = /\.(jpg|jpeg)/i.test(bisrc) ? "-rw" : "", wobp = /^(.+\/)(.*)(\/.*)$/.exec(blimg.dataset.src); blimg.dataset.srcset = wobp[1] + "w" + sssw + rwpm + "-e100" + wobp[3] + " " + sssw + "w, " + wobp[1] + "w" + lssw + rwpm + "-e100" + wobp[3] + " " + lssw + "w"; } 新しい画像URLは「-rw-e100」、古い画像URLは「-e100」のところで、画像パラメーターがカスタマイズできます。どちらの画像URLの場合も前の方がスマホ用レスポンシブ画像、後の方がパソコン用レスポンシブ画像の画像パラメーターです。 カスタマイズする場合は先頭と繋ぎに必ず半角ハイフン(-)を付けます。そして新しい画像URLの場合は分かり難いですけれども最後に半角スペース( )を必ず残して下さい。さもないと画像が表示されなくなります。 Bloggerの投稿画像の取り込みのサイズ 元のサイズ:16000pxまで取り込んだものと同じ(作成ビュー)か1600px(HTMLビュー)特大:600px大:400px中:320px小:200px 参考:Bloggerの投稿画像の種類とサイズ/容量と画像URLについて 投稿画面で特大以下のサイズで画像を取り込む場合、レスポンシブ配信の初期値は640pxか1280pxなので、ブラウザに読み込まれる画像のサイズが大きくなります。小さな画像を多用するようなブログではレスポンシブ配信の初期値を小さくするか、使わない方が良いと思居ます。使わない場合はレスポンシブ配信のソースコードを丸ごと削除して下さい。 ブログで表示される画像の大きさはレスポンシブ配信を行っても元のサイズ以外で取り込んだ場合は画像のソースコードにサイズ属性が自動的に付くために変わりません。元のサイズではそうではないためにレスポンシブ配信の大きさになります。固有のサイズで表示したい場合は投稿のHTMLビューで画像のソースコードにサイズ属性を付けるかデザインのCSSでサイズを指定するようにして下さい。 imgタグにサイズ属性を付ける例 <img src="https://..." width="480" height="320"> 横幅はwidth属性、縦幅はheight属性で、それぞれ、長さを入力して(単位なしの数値はpxとして扱われます)追加して下さい。 imgタグにCSSでサイズを指定する例 <img src="https://..." style="width:480px;height:320px;"> style属性を追加して横幅をwidth、縦幅をheightで指定します。それぞれの後に半角コロン(:)で区切って単位付きの数値を入力します。前の要素の値と次の要素は半角セミコロン(;)で区切り、最後は付けても付けなくても動作します。 CSSはその他にもstyleタグで指定する方法がありますけど、個別のHTMLタグにデザインを付けるならばstyle属性を使うのが簡単です。 参考:CSSはどう使えば良いのか|タグ自体とidとclassの指定先とstyleタグとインラインの記述法 コメント 新しい投稿 前の投稿
皆のImaginaryへの気持ちはどうなのか Blank wall with dark band above grey pavement by Maarten Deckers on Unsplash Imaginaryについて意見や感想が載せられた記事を紹介する。 テーマをずっと気になっていた「Imaginary」...
読み込みボタン/無限スクロールの手動化のカスタマイズ Imaginaryのインデックスページ、つまりトップページとアーカイブページとラベルページとブログ内の検索結果ページではスクロールが画面下に達すると次のページを自動的に読む込むという無限スクロールが搭載されています。 本稿では画面スクロールによる動作を停止して読み込みボタンで...
ブログの背景のヘッダー画像の付け方とサイズについて Bloggerでの背景のヘッダー画像の付け方 Imaginaryの背景のヘッダー画像はBloggerの管理画面のテーマのカスタマイズ(テーマデザイナー)の背景の背景画像の「背景を変更」からBloggerの既存のものを選択するか使用中のデバイスに保存してあるものをアップロードし...
ポップアップと本文に目次を追加するカスタマイズ Imaginaryの記事/追加ページの本文の画面の左下に表示される概要ボタンは本文に見出し、HTMLのh1かh2かh3の見出しタグがあった場合にそれを取り込んだ目次を自動生成して表示します。 本稿ではボップアップの目次と本文への自動生成の目次の追加とポップアップのコンテンツの...
投稿の日付表示を日本語の順番に変える方法 Imaginaryの記事ページでは記事タイトルの下に投稿の公開日、本文の下に更新日が表示されます。 日付をどのように表示するかというフォーマット(形式)はBloggerの管理画面のタイムスタンプの形式で変えることができます、 設定| Blogger 公開日と更新日の両...
インデックスページのスニペットの本文の削除と項目の並び替えのカスタマイズ Imaginaryのインデックスページ:トップとアーカイブとラベルとブログ内検索では記事のスニペットが表示されますが、初期値では記事のタイトルと画像と抜粋と二つのリンク(アーカイブと続きを読む)が表示されます。 テンプレートのデザインのカスタマイズとしてスニペットの本文の削除...
ImaginaryのBloggerブログへの付け替え方 BloggerブログにテンプレートのImaginaryを使う、すなわち既存のテンプレートから新たに付け替える方法には手順が二つある。 ImaginaryのXMLファイルをデバイスに取得する Bloggerの管理画面からテンプレートを更新する Bloggerでテンプレー...
共有ボタンのTwitterからXへの変更について Imaginaryのフローティングバーの右端の共有ボタンのTwitterをXに変更しました。2024年6月12日に行いましたが、アイコンの微調整のために翌日の13日のアップデートから十分に使えるようになりました。 TwitterがXに変わったのが2023年7月24日で、一年近...
フォント変更のためのVariableタグの一覧表 Bloggerブログのフォント(字体)はカスタマイズで変更することができます。 Bloggerブログでフォントを変更する方法 管理画面のテーマのカスタマイズのテーマデザイナーのフォントで用意された一部の英数字以外はCSSを書き換える必要があり、その場合、Imaginary...
ブログの背景画像を全画面で表示する方法 Imaginaryの通常の背景画像はおよそブログのヘッダーのみに表示されるように高さが指定されています。 背景画像の高さはBloggerの管理画面のテーマのカスタマイズの詳細設定の背景から一定の範囲内で調節することができます。 ブログの背景全体を覆い尽くすデザイン ...
コメント