最後の手段となる無料のページ速度最適化スクリプト
修正不可能なページをこの最後の手段で高速化してください。最も遅いページでも改善できる方法です。
最後の手段としての無料ページ表示速度最適化スクリプト
Core Web Vitalsコンサルタントとして、修正不可能なページに出くわすことがあります。修正方法がわからないからではありません。すでにリニューアルが決定しているサイトで、大部分の書き換えが必要になる場合があるからです。WIX、HubSpot、WebFlowのようなクローズドなCMSでは、コードを改善するためのアクセス権や制御が不十分な場合もあります。あるいは、単に予算がない場合です。頻繁にはありませんが、クライアントが必要な作業量と費用を正確に予測できないことがあります。
最終確認: Arjen Karel (2026年3月)
「最後の手段となるページ表示速度最適化スクリプト」の紹介
このような厳しい状況において、このスクリプトは表示速度を少しでも改善するための最後の手段です。新しいサイトを構築するまでのつなぎとして使用してください。仕組みとしてはMutation Observerを活用しています。ブラウザがサイトのDocument Object Modelを生成するのを監視し、遅いコードを直ちに傍受して高速なコードに置き換えます。
機能:
- すべてのrender blockingスクリプトを傍受し、スクリプトのtypeをtype="module"に変更して遅延させます。すべてのモジュールスクリプトがデフォルトで遅延される仕様を利用しています。インラインスクリプトにも適用されます。ページ内の全スクリプトを遅延させる最も安全な方法です。
- 画像のlazy loading:すべての画像にloading="lazy"とdecoding="async"を追加します。画像がviewportに入る直前まで読み込みを遅延させ、非同期で画像のレイアウトを更新します。注意:LCP画像をlazy loadingしてはいけません。prioImgs設定で除外してください。詳細はLCP画像のlazy loadingがパフォーマンスを悪化させる理由を参照してください。
- iframeのlazy loading:画像と同様に、iframeにlazy loadingを適用することで、より重要なコンテンツの読み込みを優先できます。
設定
このスクリプトは単一の「設定オブジェクト」を受け取ります。その設定を使用して、重要な画像やスクリプトの遅延やlazy loadingをスキップします。iframeの場合は逆で、設定に一致するiframeのみをlazy loadingします。すべての設定は正規表現で記述します。難しそうに聞こえるかもしれませんが、実際は非常に簡単です。
- prioScripts: srcが設定に一致するスクリプトの遅延をスキップします。
例: 'jquery|menu' はjqueryとmenuスクリプトに一致します。 - prioImgs: 画像名、クラス、またはIDが設定に一致するすべての画像のlazy loadingをスキップします。
例: 'hero' は <img id="hero" ..> と <img src="hero.jpg"> の両方に一致します。 - lazyFrames: srcが設定に一致するiframeのみをlazy loadingします。
例: 'youtube|maps' はすべてのYouTubeとGoogle Mapsのiframeをlazy loadingします。
使用方法
制限事項
前述の通り、このスクリプトをページ表示速度の根本的な解決策として使用すべきではありません。他のすべての手段が失敗し、新しいサイトを構築している間のつなぎとしてのみ許容される解決策です。
技術的に言えば、このスクリプトはブラウザ(およびプリロードスキャナ)と競合します。そのため、スクリプトが有効になる前にどの遅い要素がすでにダウンロードを開始しているかを予測することはできません。
最後の手段となるページ表示速度最適化スクリプト
本番環境用の縮小版です。
!function(t){['prioScripts', 'prioImgs', 'lazyFrames'].forEach(e=>{t[e]=t[e]?RegExp(t[e],"i"):null});let e=new MutationObserver(e=>{e.forEach(({addedNodes:e})=>{e.forEach(e=>{if(1===e.nodeType)switch(e.tagName){case"SCRIPT":if(!t.prioScripts||!t.prioScripts.test(e.src)){let t=e.getAttribute("type");t&&"text/javascript"!==t||e.setAttribute("type","module")}break;case"IMG":console.log(e.outerHTML),t.prioImgs&&(t.prioImgs.test(e.outerHTML)||e.getAttribute("loading"))||(e.setAttribute("loading","lazy"),e.setAttribute("decoding","async"));break;case"IFRAME":t.lazyFrames.test(e.src)&&e.setAttribute("loading","lazy")}})})});/MSIE|Trident/.test(navigator.userAgent)||(e.observe(document.documentElement,{childList:!0,subtree:!0}),document.addEventListener("DOMContentLoaded",()=>{e.disconnect()}))}({prioScripts:"jquery",prioImgs:"hero",lazyFrames:"youtube|maps"}); スクリプトの可読性を高めたバージョンです。本番環境では使用しないでください。縮小版を使用してください。
!function (cfg) {\r\n\r\n // Regexify config or nullify\r\n ['prioScripts', 'prioImgs', 'lazyFrames'].forEach((e) => {\r\n cfg[e] = cfg[e] ? new RegExp(cfg[e], "i") : null;\r\n });\r\n\r\n t0 = performance.now();\r\n\r\n /* Watch mutated nodes */\r\n const mutator = new MutationObserver((e) => {\r\n e.forEach(({ addedNodes: e }) => {\r\n e.forEach((e) => {\r\n switch (e.nodeType) {\r\n case 1:\r\n switch (e.tagName) {\r\n // defer scripts by adding type="module", excusive test on src\r\n case "SCRIPT":\r\n if (!cfg.prioScripts || !cfg.prioScripts.test(e.src)) {\r\n let type = e.getAttribute("type");\r\n if (!type || type === "text/javascript") {\r\n e.setAttribute("type", "module");\r\n }\r\n }\r\n break;\r\n\r\n // lazy load images, excusive test on outerHTML for classname, id etc etc\r\n case "IMG":\r\n console.log(e.outerHTML);\r\n if (!cfg.prioImgs || (!cfg.prioImgs.test(e.outerHTML) && !e.getAttribute("loading"))) {\r\n e.setAttribute("loading", "lazy");\r\n e.setAttribute("decoding", "async");\r\n }\r\n break;\r\n\r\n // lazy load iframes, inclusive test on src\r\n case "IFRAME":\r\n if (cfg.lazyFrames.test(e.src)) {\r\n e.setAttribute("loading", "lazy");\r\n }\r\n break;\r\n }\r\n break;\r\n }\r\n });\r\n });\r\n });\r\n\r\n\r\n // Check for IE\r\n if (!/MSIE|Trident/.test(navigator.userAgent)) {\r\n mutator.observe(document.documentElement, { childList: true, subtree: true });\r\n document.addEventListener("DOMContentLoaded", () => {\r\n mutator.disconnect();\r\n console.log("I quit after watching for " + (performance.now() - t0) + " ms");\r\n });\r\n }\r\n}({\r\n prioScripts: 'jquery',\r\n prioImgs: 'hero',\r\n lazyFrames: 'youtube|maps',\r\n});\r\n\r\n\r\n