問題
クライアントサイドの A/B テストツールは、ブラウザがページの構築を開始した後に DOM を変更するスクリプトを読み込むことで機能します。介入がない場合、ユーザーには元のコンテンツが短時間表示された後、テスト パターンに切り替わります。テスト プラットフォームではこれまで、テスト スクリプトが完了するか、任意のタイムアウト(通常は 4 秒)が経過するまで、opacity: 0 を使用してページ全体を非表示にする「アンチフリッカー スニペット」を使用してこの問題を回避してきました。このアプローチでは、プログレッシブ レンダリングが犠牲になり、非表示のコンテンツを誤クリックする可能性があり、不要なペイント サイクルが発生します。
ソリューション
blocking=render 属性を使用すると、<head> に配置された <script> 要素または <link> 要素は、リソースが取得されて実行されるまで、レンダリングをブロックできます(解析はブロックされません)。これにより、テスト スクリプトは、スタイルシートがデフォルトで持つレンダリング ブロック動作と同じ動作をするようになり、テスト パターンが適用されるまでブラウザがページをペイントしないようになります。不透明度のハック、任意のタイムアウト、ちらつきはありません。
実装戦略
- 必須: テスト スクリプトをドキュメント
<head>に配置し、blocking="render"を追加します。 - 必須: スクリプトに
type="module"(インライン スクリプトに推奨)またはasync(src値を持つ外部スクリプトに推奨)が含まれていることを確認します。 - 推奨事項: テスト スクリプトを小さく、高速に保ちます。スクリプトが実行されるまでレンダリングがブロックされるため、スクリプトが大きかったり遅かったりすると、最初の描画が直接遅延します。
- 最初の描画の前に実行する必要がないスクリプトには、
blocking="render"を使用しないでください。これは、最初のレンダリングで出力が表示される必要があるスクリプトのみを対象としています。 <head>以外のスクリプトにblocking="render"を適用しないでください。レンダリングをブロックできるのは、<head>内のスクリプトのみです。
実装ガイド
基本的な設定
必須: async と blocking="render" の両方を使用してテスト スクリプトを読み込みます。async 属性により、スクリプトが HTML の解析をブロックしないようにします(ブラウザはスクリプトの取得中も DOM の構築を続行します)。blocking="render" 属性は、スクリプトが実行されるまでブラウザが何も描画しないようにします。
<head>
<!--
MANDATORY: Both `async` and `blocking="render"` are required.
- `async`: Prevents parser-blocking, so the DOM is built in parallel.
- `blocking="render"`: Holds rendering until the script executes,
ensuring experiment changes are applied before the user sees anything.
-->
<script
src="https://cdn.example.com/experiment-sdk.js"
async
blocking="render"
></script>
</head>
テスト固有のスタイルを読み込んでいます
テストでバリアント スタイルシートが必要な場合は、<link> 要素で blocking="render" を使用します。<head> 内のスタイルシートは、デフォルトでレンダリングをブロックしますが、動的に挿入されたスタイルシートやスクリプトを介して追加されたスタイルシートはブロックしません。スタイルシートが動的に追加される場合や、意図を明示的に示す場合は、blocking="render" を明示的に使用します。
<head>
<!--
DO: Use blocking="render" on experiment stylesheets that are
dynamically inserted or conditionally loaded by the experiment SDK.
This ensures variant styles are applied before first paint.
-->
<link
rel="stylesheet"
href="https://cdn.example.com/experiment-variant-b.css"
blocking="render"
>
</head>
インライン テスト スクリプト
テストロジックがインライン化できるほど軽量な場合は、blocking="render" を含むインライン モジュール スクリプトを使用します。これは、テストロジックが構成を取得して DOM の変更を直接適用する場合に便利です。
<head>
<!--
DO: Use an inline module script when the experiment logic is small.
Module scripts are deferred by default (non-parser-blocking),
and blocking="render" ensures rendering waits for execution.
-->
<script type="module" blocking="render">
// Fetch the experiment configuration from your testing platform.
const config = await fetch('/api/experiment?id=homepage-cta')
.then(res => res.json());
// Apply the variant by setting a data attribute on <html>.
// CSS rules keyed to this attribute will style the variant.
document.documentElement.dataset.variant = config.variant;
</script>
<style>
/* Default styles (control group) */
.cta-button {
background-color: blue;
}
/* Variant B styles, activated by the data attribute */
[data-variant="b"] .cta-button {
background-color: green;
}
</style>
</head>
ベスト プラクティス
- 必須: テスト スクリプトは迅速に実行する必要があります。スクリプトの処理が遅いと、すべてのレンダリングが遅くなります。レンダリングを妨げるスクリプトにパフォーマンス バジェット(実行時間 100 ミリ秒未満など)を設定します。
- 推奨事項: 負荷の高いテストロジックを、レンダリングをブロックするスクリプトから分離します。バリアントを適用する、レンダリングをブロックする小さなスタブを読み込み、その後、
asyncまたはdeferを使用して(blocking="render"を使用せずに)、より重いトラッキング スクリプトまたはアナリティクス スクリプトを個別に読み込みます。 - 推奨:
<html>または<body>のデータ属性を使用して、アクティブなバリアントを通知し、その属性をキーとする CSS セレクタを使用してバリアントのスタイルを設定します。これにより、レンダリングを妨げるスクリプトで DOM を直接操作することを回避できます。 - 分析、トラッキング、その他の非視覚的なスクリプトで
blocking="render"を使用しないでください。最初の描画でユーザーに表示される内容を変更する必要があるスクリプトのみが、レンダリングをブロックする必要があります。 blocking="render"を以前のアンチフリッカー スニペットと組み合わせないでください。どちらも同じ問題を解決するためのものであり、両方を使用すると不要な遅延が発生します。
代替戦略
blocking 属性は、すべてのブラウザでサポートされているわけではありません。この属性をサポートしていないブラウザでは、属性は無視され、スクリプトはデフォルトの動作(上記の例では async)で読み込まれます。これにより、ちらつきが発生する可能性があります。サポートされていないブラウザでちらつきが発生しないようにするには、代替が必要です。
フォールバック: アンチフリッカー スニペット
推奨: blocking="render" がサポートされていない場合にのみ、フォールバックとして軽量のアンチフリッカー スニペットを使用します。サポートを機能検出して、ネイティブに処理するブラウザではフォールバックをスキップします。
<head>
<!--
DO: Load the experiment script with blocking="render" for
browsers that support it. This is the preferred approach.
-->
<script
src="https://cdn.example.com/experiment-sdk.js"
async
blocking="render"
></script>
<script>
// DO: Only apply the anti-flicker fallback in browsers
// that do not support blocking="render".
if (!Object.hasOwn(HTMLScriptElement.prototype, 'blocking')) {
// Hide the page until the experiment script runs.
document.documentElement.classList.add('ab-loading');
// DO: Set a timeout to reveal the page if the experiment
// script takes too long. This prevents an indefinitely
// blank page on slow connections. Adjust the timeout
// to match your experiment SDK's expected load time.
setTimeout(() => {
document.documentElement.classList.remove('ab-loading');
}, 4000);
}
</script>
<style>
/*
DO: Use opacity to hide content during experiment loading.
This is only applied when blocking="render" is unsupported.
*/
.ab-loading {
opacity: 0 !important;
}
</style>
</head>
// DO: In your experiment SDK's initialization callback,
// remove the fallback class to reveal the page.
function onExperimentReady() {
document.documentElement.classList.remove('ab-loading');
}
その他の注意事項
- パフォーマンスへの影響:
blocking="render"は、視覚的な正確性を優先して、最初の描画速度を犠牲にします。Largest Contentful Paint(LCP)と First Contentful Paint(FCP)をモニタリングして、テスト スクリプトによって過度な遅延が発生していないことを確認します。 - サードパーティ スクリプトの信頼性: テスト SDK がサードパーティの CDN でホストされている場合、CDN の停止によりレンダリングが完全にブロックされる可能性があります。ブラウザは独自のタイムアウト ヒューリスティック(4 秒を超える場合もあります)を適用しますが、
blocking="render"にはデベロッパーが制御するタイムアウトはありません。サードパーティ プロバイダが強力な稼働時間保証を提供していることを確認します。 - サーバーサイドの代替手段: パフォーマンスが重要なページでは、クライアントサイドのテストではなく、サーバーサイドの A/B テスト(サーバーが正しいパターンを直接レンダリングする)を検討します。サーバーサイドのアプローチでは、レンダリングをブロックするコストを発生させることなく、ちらつきを完全に排除できます。クライアントサイドの
blocking="render"は、サーバーサイドのテストが不可能な場合にのみ使用します。