Problem
Narzędzia do testów A/B po stronie klienta działają przez wczytanie skryptu, który modyfikuje DOM, gdy przeglądarka zacznie już tworzyć stronę. Bez interwencji użytkownik przez chwilę widzi oryginalną treść, zanim zacznie ona migotać lub migać, przechodząc do wariantu eksperymentalnego. Platformy testowe zwykle radziły sobie z tym problemem za pomocą „fragmentów kodu zapobiegających migotaniu”, które ukrywają całą stronę za pomocą opacity: 0, dopóki skrypt eksperymentu nie zakończy działania lub nie upłynie określony czas oczekiwania (zwykle 4 sekundy). Takie podejście uniemożliwia renderowanie progresywne, pozwala na przypadkowe kliknięcia niewidocznych treści i wprowadza niepotrzebne cykle renderowania.
Rozwiązanie
Atrybut blocking=render umożliwia elementowi <script> lub <link> umieszczonemu w <head> blokowanie renderowania (ale nie analizowania) do czasu pobrania i wykonania zasobu. Dzięki temu skrypty eksperymentów mają takie samo zachowanie blokujące renderowanie jak arkusze stylów, co gwarantuje, że przeglądarka nigdy nie wyrenderuje strony, dopóki nie zostanie zastosowany wariant eksperymentu. Bez sztuczek z przezroczystością, bez arbitralnych limitów czasu i bez migotania.
Strategia wdrażania
- OBOWIĄZKOWO: umieść skrypt eksperymentu w dokumencie
<head>i dodajblocking="render". - OBOWIĄZKOWO: upewnij się, że skrypt ma wartość
type="module"(preferowaną w przypadku skryptów wbudowanych) lubasync(preferowaną w przypadku skryptów zewnętrznych z wartościąsrc). - ZALECANE: skrypt eksperymentu powinien być mały i szybki. Renderowanie jest blokowane do momentu wykonania skryptu, więc duży lub wolny skrypt bezpośrednio opóźnia pierwsze wyrenderowanie.
- NIE używaj
blocking="render"w przypadku skryptów, które nie muszą być uruchamiane przed pierwszym wyrenderowaniem. Jest przeznaczony tylko do skryptów, których dane wyjściowe muszą być widoczne w początkowym renderowaniu. - NIE stosuj
blocking="render"do skryptów poza<head>. Tylko skrypty w<head>mogą blokować renderowanie.
Przewodnik po implementacji
Konfiguracja podstawowa
OBOWIĄZKOWO: wczytaj skrypt eksperymentu z użyciem parametrów async i blocking="render". Atrybut async sprawia, że skrypt nie blokuje analizowania kodu HTML (przeglądarka kontynuuje tworzenie DOM podczas pobierania skryptu). Atrybut blocking="render" sprawia, że przeglądarka nie renderuje niczego, dopóki skrypt nie zostanie wykonany.
<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>
Wczytywanie stylów eksperymentalnych
Jeśli eksperyment wymaga arkusza stylów wariantu, użyj blocking="render" w elemencie <link>. Arkusze stylów w elemencie <head> domyślnie blokują renderowanie, ale arkusze stylów wstrzykiwane dynamicznie lub dodawane za pomocą skryptu tego nie robią. Używaj blocking="render", gdy arkusz stylów jest dodawany dynamicznie lub gdy chcesz wyraźnie określić zamiar.
<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>
Skrypt eksperymentu wbudowanego
Jeśli logika eksperymentu jest na tyle prosta, że można ją umieścić w kodzie, użyj skryptu modułu wbudowanego z atrybutem blocking="render". Jest to przydatne, gdy logika eksperymentu pobiera konfigurację i bezpośrednio stosuje zmiany w modelu 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>
Sprawdzone metody
- OBOWIĄZKOWO: skrypt eksperymentu MUSI być wykonywany szybko. Powolny skrypt opóźnia renderowanie wszystkich elementów. Ustaw budżet wydajności (np. czas wykonywania poniżej 100 ms) dla skryptu blokującego renderowanie.
- DO split heavy experiment logic from the render-blocking script. Wczytaj mały, blokujący renderowanie kod, który stosuje wariant, a następnie wczytaj osobno cięższe skrypty śledzenia lub analizy za pomocą
asynclubdefer(bezblocking="render"). - UŻYWAJ atrybutu danych w tagu
<html>lub<body>, aby wskazać aktywny wariant, i używaj selektorów CSS powiązanych z tym atrybutem do stylizacji wariantu. Pozwala to uniknąć bezpośredniego manipulowania modelem DOM w skrypcie blokującym renderowanie. - NIE używaj atrybutu
blocking="render"w skryptach analitycznych, śledzących ani innych skryptach niewizualnych. Renderowanie powinny blokować tylko skrypty, które muszą zmienić to, co użytkownik widzi przy pierwszym wyrenderowaniu. - NIE łącz
blocking="render"ze starszymi fragmentami kodu zapobiegającymi migotaniu. Rozwiązują ten sam problem, a używanie obu powoduje niepotrzebne opóźnienia.
Strategie zastępcze
Atrybut blocking nie jest obsługiwany we wszystkich przeglądarkach. W przeglądarkach, które go nie obsługują, atrybut jest ignorowany, a skrypt wczytuje się zgodnie z działaniem domyślnym (async w powyższych przykładach), co może powodować migotanie. Aby zapobiec migotaniu w nieobsługiwanych przeglądarkach, wymagana jest kreacja zastępcza.
Rozwiązanie rezerwowe: kod zapobiegający migotaniu
ZALECANE: używaj lekkiego fragmentu kodu zapobiegającego migotaniu jako rozwiązania zastępczego tylko wtedy, gdy interfejs blocking="render" nie jest obsługiwany. Wykrywaj obsługę funkcji i pomijaj kreację zastępczą w przeglądarkach, które obsługują ją natywnie.
<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');
}
Inne rzeczy, które warto wziąć pod uwagę
- Wpływ na wydajność:
blocking="render"przedkłada poprawność wizualną nad szybkość pierwszego wyrenderowania. Monitoruj największe wyrenderowanie treści (LCP) i pierwsze wyrenderowanie treści (FCP), aby upewnić się, że skrypt eksperymentu nie powoduje nadmiernego opóźnienia. - Niezawodność skryptów innych firm: jeśli pakiet SDK eksperymentu jest hostowany w sieci CDN innej firmy, awaria sieci CDN może całkowicie zablokować renderowanie. Przeglądarka stosuje własne heurystyki czasu oczekiwania (które mogą być dłuższe niż 4 sekundy), ale nie ma czasu oczekiwania kontrolowanego przez dewelopera dla
blocking="render". Upewnij się, że dostawca zewnętrzny gwarantuje wysoki poziom dostępności. - Alternatywy po stronie serwera: w przypadku stron, na których wydajność ma kluczowe znaczenie, rozważ testy A/B po stronie serwera (gdzie serwer bezpośrednio renderuje prawidłowy wariant) zamiast testów po stronie klienta. Podejścia po stronie serwera całkowicie eliminują migotanie bez jakiegokolwiek narzutu związanego z blokowaniem renderowania.
blocking="render"po stronie klienta używaj tylko wtedy, gdy testowanie po stronie serwera nie jest możliwe.