المشكلة
تعمل أدوات اختبار A/B من جهة العميل من خلال تحميل نص برمجي يعدّل نموذج العناصر في المستند (DOM) بعد أن يبدأ المتصفّح في إنشاء الصفحة. بدون تدخّل، يرى المستخدم المحتوى الأصلي لفترة وجيزة قبل أن يومض أو يظهر بسرعة إلى صيغة التجربة. في السابق، كانت منصات الاختبار تتجنّب هذه المشكلة باستخدام "مقتطفات منع الوميض" التي تخفي الصفحة بأكملها باستخدام opacity: 0 إلى أن ينتهي نص التجربة البرمجي أو تنقضي مهلة عشوائية (عادةً 4 ثوانٍ). يؤدي هذا النهج إلى التضحية بالعرض التدريجي، ويسمح بالنقرات غير المقصودة على المحتوى غير المرئي، ويقدّم دورات رسم غير ضرورية.
الحل
تسمح السمة blocking=render لعنصر <script> أو <link> موضوع في <head> بحظر العرض، وليس التحليل، إلى أن يتم جلب المورد وتنفيذه. يمنح ذلك نصوص التجربة البرمجية سلوك حظر العرض نفسه الذي تتّبعه أوراق الأنماط تلقائيًا، ما يضمن عدم عرض المتصفّح للصفحة أبدًا إلى أن يتم تطبيق صيغة التجربة. لا حاجة إلى استخدام حيل التعتيم أو مهلات عشوائية، ولن يحدث أي وميض.
استراتيجية التنفيذ
- إلزامي: ضَع نص التجربة البرمجي في المستند
<head>وأضِفblocking="render". - إجراء إلزامي: تأكَّد من أنّ النص البرمجي يحتوي على
type="module"(يُفضَّل استخدامه للنصوص البرمجية المضمّنة) أوasync(يُفضَّل استخدامه للنصوص البرمجية الخارجية التي تتضمّن قيمةsrc). - يجب أن يكون نص التجربة صغيرًا وسريعًا. بما أنّ العرض محظور إلى أن يتم تنفيذ النص البرمجي، فإنّ النص البرمجي الكبير أو البطيء يؤخّر مباشرةً أول عرض للمحتوى.
- لا تستخدِم
blocking="render"في النصوص البرمجية التي لا تحتاج إلى التشغيل قبل العرض الأول. وهي مخصّصة فقط للنصوص البرمجية التي يجب أن يكون ناتجها مرئيًا في العرض الأولي. - لا تطبّق
blocking="render"على النصوص البرمجية خارج<head>. يمكن فقط للنصوص البرمجية في<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>
جارٍ تحميل الأنماط الخاصة بالتجربة
إذا كانت التجربة تتطلّب ورقة أنماط مختلفة، استخدِم blocking="render" في العنصر <link>. تحظر أوراق الأنماط في <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"سرعة العرض الأول على الدقة المرئية. راقِب مقياسَي "سرعة عرض أكبر محتوى مرئي" (LCP) و"سرعة عرض أول محتوى مرئي" (FCP) للتأكّد من أنّ النص البرمجي للتجربة لا يضيف تأخيرًا مفرطًا. - موثوقية النصوص البرمجية التابعة لجهات خارجية: إذا كانت حزمة تطوير البرامج (SDK) الخاصة بالتجربة مستضافة على شبكة توصيل محتوى (CDN) تابعة لجهة خارجية، قد يؤدي انقطاع خدمة الشبكة إلى حظر العرض بالكامل. يطبّق المتصفّح أساليب الاستدلال الخاصة به لمهلة الانتظار (والتي قد تكون أطول من 4 ثوانٍ)، ولكن لا تتوفّر مهلة انتظار يتحكّم فيها المطوّر لـ
blocking="render". تأكَّد من أنّ مقدّم الخدمة الخارجي يقدّم ضمانات قوية بشأن مدة التشغيل. - البدائل من جهة الخادم: بالنسبة إلى الصفحات التي يكون فيها الأداء بالغ الأهمية، ننصحك بإجراء اختبارات A/B من جهة الخادم (حيث يعرض الخادم الصيغة الصحيحة مباشرةً) بدلاً من الاختبارات من جهة العميل. تتجنّب الأساليب من جهة الخادم الوميض تمامًا بدون أي تكلفة لحظر العرض. استخدِم
blocking="render"من جهة العميل فقط عندما يتعذّر إجراء الاختبار من جهة الخادم.