Pengujian A/B Sisi Klien Bebas Kedipan

Fitur web: blocking="render"

Masalah

Alat pengujian A/B sisi klien berfungsi dengan memuat skrip yang mengubah DOM setelah browser mulai membuat halaman. Tanpa intervensi, pengguna akan melihat konten asli secara singkat sebelum konten tersebut berkedip atau beralih ke varian eksperimen. Platform pengujian biasanya mengatasi hal ini dengan "cuplikan anti-pergantian tampilan halaman" yang menyembunyikan seluruh halaman dengan opacity: 0 hingga skrip eksperimen selesai atau waktu tunggu arbitrer (biasanya 4 detik) berlalu. Pendekatan ini mengorbankan rendering progresif, memungkinkan klik yang tidak disengaja pada konten yang tidak terlihat, dan menyebabkan siklus render yang tidak perlu.

Solusi

Atribut blocking=render memungkinkan elemen <script> atau <link> yang ditempatkan di <head> memblokir rendering—tetapi tidak memblokir penguraian—hingga resource diambil dan dieksekusi. Hal ini memberi skrip eksperimen perilaku pemblokiran render yang sama dengan yang dimiliki stylesheet secara default, sehingga memastikan browser tidak pernah merender halaman hingga varian eksperimen diterapkan. Tanpa peretasan opasitas, tanpa waktu tunggu arbitrer, dan tanpa kedipan.

Strategi Penerapan

  1. WAJIB: Tempatkan skrip eksperimen di <head> dokumen dan tambahkan blocking="render".
  2. WAJIB: Pastikan skrip memiliki type="module" (lebih disukai untuk skrip inline) atau async (lebih disukai untuk skrip eksternal dengan nilai src).
  3. LAKUKAN: Buat skrip eksperimen tetap kecil dan cepat. Karena rendering diblokir hingga skrip dieksekusi, skrip yang besar atau lambat akan langsung menunda first paint.
  4. JANGAN gunakan blocking="render" pada skrip yang tidak perlu dijalankan sebelum first paint. Atribut ini hanya ditujukan untuk skrip yang output-nya harus terlihat dalam render awal.
  5. JANGAN menerapkan blocking="render" ke skrip di luar <head>. Hanya skrip di <head> yang dapat memblokir rendering.

Panduan Penerapan

Penyiapan Dasar

WAJIB: Muat skrip eksperimen dengan async dan blocking="render". Atribut async memastikan skrip tidak memblokir penguraian HTML (browser terus membangun DOM saat mengambil skrip). Atribut blocking="render" memastikan browser tidak merender apa pun hingga skrip dieksekusi.

<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>

Memuat Gaya Khusus Eksperimen

Jika eksperimen memerlukan stylesheet varian, gunakan blocking="render" pada elemen <link>. Stylesheet di <head> sudah memblokir rendering secara default, tetapi stylesheet yang dimasukkan secara dinamis atau yang ditambahkan melalui skrip tidak. Gunakan blocking="render" secara eksplisit saat stylesheet ditambahkan secara dinamis atau saat Anda ingin memperjelas maksudnya.

<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>

Skrip Eksperimen Inline

Jika logika eksperimen cukup ringan untuk di-inline, gunakan skrip modul inline dengan blocking="render". Hal ini berguna saat logika eksperimen mengambil konfigurasi dan menerapkan perubahan DOM secara langsung.

<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>

Praktik Terbaik

  • WAJIB: Skrip eksperimen HARUS dijalankan dengan cepat. Skrip yang lambat akan menunda semua rendering. Tetapkan anggaran performa (misalnya, waktu eksekusi di bawah 100 md) untuk skrip yang memblokir render.
  • LAKUKAN pemisahan logika eksperimen yang berat dari skrip pemblokir render. Muat stub kecil yang memblokir rendering yang menerapkan varian, lalu muat skrip pelacakan atau analisis yang lebih berat secara terpisah dengan async atau defer (tanpa blocking="render").
  • LAKUKAN penggunaan atribut data pada <html> atau <body> untuk menandai varian aktif, dan gunakan pemilih CSS yang terkait dengan atribut tersebut untuk penataan gaya varian. Hal ini menghindari manipulasi DOM langsung dalam skrip yang memblokir rendering.
  • JANGAN gunakan blocking="render" pada skrip analisis, pelacakan, atau skrip non-visual lainnya. Hanya skrip yang harus mengubah apa yang dilihat pengguna pada render pertama yang boleh memblokir rendering.
  • JANGAN gabungkan blocking="render" dengan cuplikan anti-pergantian tampilan halaman lama. Keduanya menyelesaikan masalah yang sama; menggunakan keduanya akan menimbulkan penundaan yang tidak perlu.

Strategi Penggantian

Atribut blocking tidak didukung di semua browser. Di browser yang tidak mendukungnya, atribut akan diabaikan dan skrip akan dimuat dengan perilaku defaultnya (async dalam contoh di atas), yang dapat menyebabkan kedipan. Penggantian diperlukan untuk mencegah kedipan di browser yang tidak didukung.

Penggantian: Cuplikan Anti-Pergantian Tampilan Halaman

LAKUKAN: Gunakan cuplikan anti-pergantian tampilan halaman yang ringan sebagai pengganti hanya jika blocking="render" tidak didukung. Deteksi dukungan fitur dan lewati penggantian di browser yang menanganinya secara native.

<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');
}

Pertimbangan Lainnya

  1. Dampak Performa: blocking="render" mengorbankan kecepatan first-paint demi kebenaran visual. Pantau Largest Contentful Paint (LCP) dan First Contentful Paint (FCP) untuk memastikan skrip eksperimen tidak menambahkan penundaan yang berlebihan.
  2. Keandalan Skrip Pihak Ketiga: Jika SDK eksperimen dihosting di CDN pihak ketiga, pemadaman layanan CDN dapat memblokir rendering sepenuhnya. Browser menerapkan heuristik waktu tunggunya sendiri (yang mungkin lebih lama dari 4 detik), tetapi tidak ada waktu tunggu yang dikontrol developer untuk blocking="render". Pastikan penyedia pihak ketiga memiliki jaminan waktu beroperasi yang kuat.
  3. Alternatif Sisi Server: Untuk halaman yang sangat mementingkan performa, pertimbangkan pengujian A/B sisi server (tempat server merender varian yang benar secara langsung) daripada pengujian sisi klien. Pendekatan sisi server menghilangkan kedipan sepenuhnya tanpa biaya pemblokiran render. Gunakan blocking="render" sisi klien hanya jika pengujian sisi server tidak memungkinkan.