إصلاح عدم ثبات التنسيق

جولة تفصيلية حول استخدام WebPageTest لتحديد مشاكل عدم ثبات التنسيق وإصلاحها

وقد كتبت في مشاركة سابقة حول قياس متغيّرات التصميم التراكمية (CLS) في WebPageTest. متغيّرات التصميم التراكمية(CLS) هي عبارة عن تجميع لكل متغيّرات التصميم، لذا اعتقدت في هذه المشاركة أنّه سيكون من المثير للاهتمام التعمق أكثر وفحص كل متغيّر تصميم فردي على الصفحة لمحاولة فهم السبب الذي يمكن أن يتسبب في عدم الاستقرار ومحاولة حلّ المشاكل.

قياس تغييرات التصميم

باستخدام واجهة Layout Instability API، يمكننا الحصول على قائمة بجميع أحداث متغيّرات التصميم في صفحة معيّنة:

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

يؤدي ذلك إلى إنشاء صفيف من متغيّرات التصميم التي لا يسبقها أحداث إدخال:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

في هذا المثال، حدث تغيير واحد صغير جدًا بنسبة 0.01% في 210 ملي ثانية.

من المفيد معرفة وقت التحول وشدته للمساعدة في تضييق نطاق الأسباب المحتمَلة للتحول. لنعود إلى WebPageTest للحصول على بيئة اختبار لإجراء المزيد من الاختبارات.

قياس متغيّرات التصميم في WebPageTest

على غرار قياس متغيّرات التصميم التراكمية في WebPageTest، سيتطلب قياس متغيّرات التصميم الفردية مقياسًا مخصّصًا. لحسن الحظ، أصبحت العملية أسهل الآن بعد أن أصبح الإصدار 77 من Chrome ثابتًا. تكون واجهة برمجة التطبيقات Layout Instability API مفعّلة تلقائيًا، لذا من المفترض أن تتمكّن من تنفيذ مقتطف JavaScript هذا على أي موقع إلكتروني في Chrome 77 والحصول على النتائج على الفور. في WebPageTest، يمكنك استخدام متصفّح Chrome التلقائي بدون القلق بشأن علامات سطر الأوامر أو استخدام Canary.

لنعدِّل هذا النص البرمجي لإنشاء مقياس مخصّص لخدمة WebPageTest:

[LayoutShifts]
return new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
  }).observe({type: "layout-shift", buffered: true});
});

يُحلّ الوعد في هذا النص البرمجي إلى تمثيل JSON للصفيف بدلاً من الصفيف نفسه. ويرجع ذلك إلى أنّ المقاييس المخصّصة لا يمكنها إنشاء أنواع بيانات أساسية إلّا مثل السلاسل أو الأرقام.

الموقع الإلكتروني الذي سأستخدمه في الاختبار هو ismyhostfastyet.com، وهو موقع أنشأته لمقارنة أداء التحميل الفعلي لمضيفي الويب.

تحديد أسباب عدم ثبات التنسيق

في النتائج، يمكننا رؤية المقياس المخصّص LayoutShifts له القيمة التالية:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

باختصار، هناك تغيُّر واحد في التصميم بنسبة %34.2 يحدث بعد 3087 ملي ثانية. للمساعدة في تحديد السبب، لنستخدِم عرض الشريط السينمائي في WebPageTest.

خليتان في شريط الصور، تعرض لقطات شاشة قبل وبعد تغيير التنسيق
خليتان في شريط الصور، تعرض لقطات شاشة قبل تغيير التنسيق وبعده

عند الانتقال إلى علامة 3 ثوانٍ تقريبًا في شريط الصور، يظهر لنا سبب تغيُّر التنسيق بنسبة %34، وهو الجدول الملوّن. يجلب الموقع الإلكتروني ملف JSON بشكل غير متزامن، ثم يعرضه في جدول. يكون الجدول فارغًا في البداية، لذا فإنّ انتظار ملئه عند تحميل النتائج هو ما يؤدي إلى حدوث التغيير.

ظهور عنوان خط الويب من العدم
عنوان خط الويب يظهر من العدم:

ولكن هذا ليس كل شيء. عندما تكتمل الصفحة مرئيةً بعد 4.3 ثانية تقريبًا، يمكننا أن نرى أنّ <h1> الصفحة "هل المضيف سريع بعد؟" تظهر من العدم. ويحدث ذلك لأنّ الموقع الإلكتروني يستخدم خط ويب ولم يتّخذ أي خطوات لتحسين العرض. لا يبدو أنّ التنسيق يتغيّر عند حدوث ذلك، ولكنّ تجربة المستخدم لا تزال سيئة إذا كان عليه الانتظار لمدة طويلة لقراءة العنوان.

إصلاح عدم ثبات التنسيق

والآن بعد أن عرفنا أن الجدول الذي يتم إنشاؤه بشكل غير متزامن يتسبب في تغيُّر ثلث إطار العرض، فقد حان الوقت لإصلاحه. لا نعرف محتوى الجدول إلى أن يتم تحميل نتائج JSON فعلاً، ولكن لا يزال بإمكاننا تعبئة الجدول بنوع من بيانات العنصر النائب بحيث يكون التنسيق نفسه مستقرًا نسبيًا عند عرض DOM.

في ما يلي الرمز لإنشاء بيانات نائبة:

function getRandomFiller(maxLength) {
  var filler = '█';
  var len = Math.ceil(Math.random() * maxLength);
  return new Array(len).fill(filler).join('');
}

function getRandomDistribution() {
  var fast = Math.random();
  var avg = (1 - fast) * Math.random();
  var slow = 1 - (fast + avg);
  return [fast, avg, slow];
}

// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
  var [fast, avg, slow] = getRandomDistribution();
  window.data.push({
    platform: getRandomFiller(10),
    client: getRandomFiller(5),
    n: getRandomFiller(1),
    fast,
    avg,
    slow
  });
}
updateResultsTable(sortResults(window.data, 'fast'));

يتم إنشاء بيانات العنصر النائب بشكل عشوائي قبل فرزها. حيث يتضمن الحرف "█" الذي يكرر عدد عشوائي من المرات لإنشاء عناصر نائبة مرئية للنص وتوزيع عشوائي للقيم الرئيسية الثلاث. أضفت أيضًا بعض الأنماط لإلغاء تشبُّع كل الألوان من الجدول لتوضيح أن البيانات لم يتم تحميلها بالكامل حتى الآن.

لا يهمّ مظهر العناصر النائبة التي تستخدمها للحفاظ على ثبات التنسيق. الغرض من العناصر النائبة هو طمأنة المستخدمين بأنّ المحتوى سيكون متاحًا وأنّ الصفحة تعمل بشكل سليم.

في ما يلي شكل العناصر النائبة أثناء تحميل بيانات JSON:

يتم عرض جدول البيانات مع بيانات العنصر النائب.
يتم عرض جدول البيانات باستخدام بيانات العناصر النائبة.

وتكون معالجة مشكلة خطوط الويب أكثر بساطةً. بما أنّ الموقع الإلكتروني يستخدم خطوط Google، ما عليك سوى إدخال السمة display=swap في طلب CSS. هذا كلّ ما في الأمر. ستضيف Fonts API نمط font-display: swap في تعريف الخط، ما يتيح للمتصفّح عرض النص بخط احتياطي على الفور. في ما يلي الترميز المناسب مع الإصلاح المضمّن:

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

التحقّق من التحسينات

بعد إعادة تشغيل الصفحة من خلال WebPageTest، يمكننا إنشاء مقارنة بين الأداء قبل إجراء التغيير وبعده لعرض الفرق وقياس درجة عدم استقرار التنسيق الجديدة:

شريط أفلام WebPageTest يعرض تحميل كلا الموقعَين الإلكترونيَين جنبًا إلى جنب مع تحسينات التنسيق وبدونها
شريط أفلام WebPageTest يعرض تحميل الموقعَين الإلكترونيَين جنبًا إلى جنب مع تحسينات التنسيق وبدونها
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

وفقًا للمقياس المخصّص، لا يزال هناك تغيُّر في التصميم يحدث بعد 3071 ملي ثانية (تقريبًا الوقت نفسه كما في السابق)، ولكنّ شدة التغيُّر أصغر بكثير: 0.005%. لا بأس بذلك.

ويتضح أيضًا من شريط الصور أنّ الخط <h1> يتم عرضه على الفور إلى أحد خطوط النظام، ما يتيح للمستخدمين قراءته بشكل أسرع.

الخاتمة

من المحتمل أن تواجه المواقع الإلكترونية المعقدة تغييرات في التنسيق أكثر بكثير مما هو موضّح في هذا المثال، ولكن تظلّ عملية الإصلاح كما هي: إضافة مقاييس عدم استقرار التنسيق إلى WebPageTest، والرجوع إلى النتائج باستخدام شريط تحميل مرئي لتحديد العناصر المسببة للمشكلة، وتنفيذ حلّ باستخدام العناصر النائبة لحجز مساحة الشاشة.

(نقطة أخرى) قياس عدم ثبات التنسيق الذي يواجهه المستخدمون الفعليون

من الجيد أن تتمكّن من تشغيل WebPageTest على صفحة قبل إجراء عملية تحسين وبعدها، وأن تلاحظ تحسّنًا في أحد المقاييس، ولكن ما يهمّ حقًا هو أنّ تجربة المستخدم تتحسن فعليًا. أليس هذا هو السبب في أنّنا نحاول تحسين الموقع الإلكتروني في المقام الأول؟

لذا، الأمر الذي سيكون رائعًا إذا بدأنا في قياس تجارب عدم استقرار التنسيق للمستخدمين الحقيقيين إلى جانب مقاييس أداء الويب التقليدية لدينا. هذه الخطوة مهمة جدًا في حلقة الملاحظات والآراء حول التحسين، لأنّ الحصول على بيانات من تجارب المستخدمين الحقيقيين يُطلعنا على المشاكل التي تواجههم وما إذا كانت الإصلاحات التي أجريناها قد أحدثت فرقًا إيجابيًا.

بالإضافة إلى جمع بيانات عدم استقرار التنسيق، يمكنك الاطّلاع على تقرير تجربة المستخدم في Chrome الذي يتضمّن بيانات "التغيير التراكمي في التنسيق" من تجارب المستخدمين الفعلية على ملايين المواقع الإلكترونية. ويتيح لك هذا التقرير معرفة مستوى أدائك (أو أداء منافسيك)، أو يمكنك استخدامه لاستكشاف حالة عدم ثبات التنسيق على الويب.