كيف نبني مواقع ويب سريعة: دليل ميداني لمؤشرات Core Web Vitals
مؤشرات Core Web Vitals ليست لوحة نتائج، بل هي وعد لمستخدميك. إليك بالضبط كيف نبني مواقع ويب سريعة في Innovation T، من استراتيجية الصور إلى تفعيل WebGL بشكل مشروط على الأجهزة القادرة.
بقلم Innovation T Team
الموقع البطيء يفقد الناس قبل أن تتاح له فرصة إقناعهم أصلاً. شخص ما يضغط على رابطك من هاتف أندرويد متوسط الفئة عبر اتصال ضعيف، ينتظر، يرى التخطيط يقفز في كل اتجاه، يضغط على زر لا يفعل شيئاً لمدة نصف ثانية، ثم يغادر. لا يصمد أي نص مقنع أمام هذه التجربة. في Innovation T نتعامل مع الأداء بوصفه ميزة من ميزات المنتج، لا مهمة تنظيف لاحقة، ومؤشرات Core Web Vitals هي اللغة التي يمنحنا إياها Google لقياسه.
هذا هو الدليل الميداني الذي نستخدمه فعلاً حين نبني. يشرح ما تعنيه المؤشرات بعبارات بسيطة، ثم يقدم لك الأساليب الملموسة التي نلجأ إليها في المشاريع الحقيقية.
ما الذي تقيسه المؤشرات فعلاً
مؤشرات Core Web Vitals هي ثلاثة مؤشرات محورها المستخدم، إضافة إلى مؤشر مخبري واحد يساعدك على اكتشاف المشكلات قبل أن يكتشفها مستخدموك. انسَ الاختصارات لحظة وفكّر فيما يشعر به المستخدم.
LCP (Largest Contentful Paint) يجيب عن سؤال بسيط: كم من الوقت يمر قبل أن يظهر العنصر الرئيسي في هذه الصفحة؟ هذا "العنصر الرئيسي" هو عادةً صورة رئيسية أو عنوان أو كتلة نصية كبيرة. إذا كان LCP لديك أربع ثوانٍ، فإن زائرك يحدّق في شاشة شبه فارغة لمدة أربع ثوانٍ. تعتبر Google أن 2.5 ثانية أو أقل نتيجة جيدة.
INP (Interaction to Next Paint) يقيس مدى الاستجابة. حين يضغط أحدهم أو ينقر أو يكتب، كم من الوقت يمر قبل أن تتفاعل الصفحة بشكل مرئي؟ حلّ INP محل مؤشر First Input Delay الأقدم لأنه ينظر إلى جميع التفاعلات على مدى الزيارة، لا التفاعل الأول فحسب. زر بطيء، قائمة تنفتح متأخرة قليلاً، حقل نموذج متقطع: هذا هو INP السيئ. النتيجة الجيدة هي 200 ميلي ثانية أو أقل.
CLS (Cumulative Layout Shift) يقيس الاستقرار البصري. إنه إحباط قراءة فقرة ثم رؤيتها تقفز لأن صورة أو إعلاناً تحمّل فوقها، أو مدّ يدك نحو زر ينزلق فجأة من تحت إصبعك. الـ CLS الجيد هو 0.1 أو أقل.
TBT (Total Blocking Time) هو النظير المخبري لمؤشر INP. يقيس المدة التي كان فيها الـ main thread محجوباً وغير قادر على الاستجابة أثناء تحميل الصفحة. سترى TBT في Lighthouse وأدوات مخبرية أخرى. ارتفاع TBT يتنبأ غالباً بضعف INP في الميدان، لذا نستخدمه إنذاراً مبكراً أثناء التطوير.
النمط هنا مهم. يتعلق LCP بالتحميل، ويتعلق INP وTBT بالتفاعلية، ويتعلق CLS بالاستقرار. معظم أعمال الأداء تتلخص في إرسال أقل ما يمكن إلى المتصفح والقيام بعمل أقل على الـ main thread. كل ما يلي هو صيغة من هاتين الفكرتين.
استراتيجية الصور: عادةً أكبر مكسب
الصور هي أثقل شيء في معظم الصفحات، والصورة الرئيسية كثيراً ما تكون عنصر LCP، ولهذا نبدأ من هنا.
- قدّم صيغاً حديثة. صيغتا AVIF وWebP أصغر بكثير من JPEG أو PNG عند الجودة نفسها. نقدّم AVIF مع بديل احتياطي بصيغة WebP ولا نلجأ إلى الصيغ الأقدم إلا حين نكون مضطرين حقاً.
- اضبط أحجام الصور على حجم عرضها وقدّم نسخاً متجاوبة. استخدم
srcsetوsizesكي يحمّل الهاتف صورة بحجم الهاتف، لا صورة سطح مكتب بعرض 2000 بكسل مصغّرة داخل المتصفح. - حدّد دائماً
widthوheightصريحين (أوaspect-ratioفي CSS). هذا يحجز المساحة قبل تحميل الصورة وهو الإصلاح الأكثر فعالية على الإطلاق لمؤشر CLS. - امنح الأولوية لصورة LCP وحمّل البقية بشكل مؤجل. أضف
fetchpriority="high"إلى الصورة الرئيسية وloading="lazy"إلى كل ما هو أسفل حد الطي كي لا تتنافس الصور خارج الشاشة على عرض النطاق أثناء الرسم الأول الحرج. - فكّر في تلميح تحميل مسبق (preload) للصورة الرئيسية كي يبدأ المتصفح بجلبها قبل أن ينتهي من تحليل الـ CSS.
ضبط الصورة الرئيسية بشكل صحيح كثيراً ما يخفض LCP وحده إلى ما دون حاجز 2.5 ثانية. تنطبق الصرامة نفسها على الفيديو: استخدم صورة ملصق (poster)، ولا تشغّل تلقائياً فيديو خلفية ثقيلاً على الهاتف المحمول أبداً.
تحميل الخطوط: أوقف النص غير المرئي
خطوط الويب قاتل صامت لمؤشري LCP وCLS. تنتظر الصفحة خطاً مخصصاً، فلا تعرض شيئاً (أو تعرض نصاً احتياطياً يُعاد تدفقه بعد ذلك)، ويدفع المستخدم الثمن.
- أضف
font-display: swapكي يُعرض النص فوراً بخط احتياطي ثم يتبدّل إلى خط الويب عند وصوله. يستطيع المستخدمون القراءة أثناء تحميل الخط. - استضف خطوطك ذاتياً بدلاً من جلبها من طرف ثالث. هذا يلغي اتصالاً إضافياً ويمنحك التحكم في التخزين المؤقت.
- حمّل مسبقاً ملف أو ملفي الخط الحرجين كي يبدأ تنزيلهما مبكراً.
- اقتصر على مجموعة جزئية (subset) من الخطوط تشمل الأحرف والأوزان التي تستخدمها فعلاً. تقديم كل وزن من عائلة خطوط بينما تستخدم وزنين هو هدر محض.
- اختر خطاً احتياطياً بمقاييس مشابهة، أو اضبطه بخاصية
size-adjust، كي لا يسبب التبديل إعادة تدفق مرئية. هذا يحمي مؤشر CLS.
تقليل JavaScript على الـ main thread
JavaScript هو المكان الذي يموت فيه INP وTBT الجيدان. كل سكربت يتوجب على المتصفح تحليله وترجمته وتنفيذه يشغل الـ main thread، وطالما كان هذا الـ thread مشغولاً فلا يمكنه الاستجابة للنقرات. هذا هو المجال الأصعب والأكثر قيمة لإتقانه.
- أرسل أقل. دقّق في الـ bundle واحذف التبعيات التي لا تحتاجها. مكتبة تواريخ، طقم واجهة ضخم مستخدم لمكوّن واحد، ثلاث مكتبات أدوات متداخلة: هذه تتراكم بسرعة.
- قسّم الشيفرة (code splitting) وحمّلها بشكل مؤجل. حمّل JavaScript الخاص بمسار أو مكوّن فقط عند الحاجة إليه، لا كله مقدماً. النافذة المنبثقة التي تنفتح بالنقر لا حاجة لوجودها في الـ bundle الأولي.
- أجّل السكربتات غير الحرجة. ينبغي لأدوات التحليلات وودجت الدردشة ووسوم التسويق أن تُحمّل بعد أن تصبح الصفحة تفاعلية، لا أن تنافسها. استخدم
deferأو حمّلها عند الخمول (on idle). - جزّئ المهام الطويلة. أي مهمة تتجاوز 50 ميلي ثانية تحجب التفاعل. جزّئ العمل الثقيل وأعِد التحكم إلى الـ main thread كي يتمكن المتصفح من الاستجابة للمدخلات بين الأجزاء.
- فضّل المنصة. الكثير مما يثبّت الناس المكتبات من أجله (التحقق من النماذج، الحركة البسيطة، تنسيق التواريخ) صار المتصفح يؤديه أصلاً بشكل أصلي. نبني صفحات عالية التحويل بشيفرة أقل، وهو موضوع نتناوله في دليلنا حول تشريح صفحة هبوط عالية التحويل.
تفعيل مكتبات WebGL والحركة الثقيلة بشكل مشروط
هنا تفصل الخبرة الميدانية المواقع الجيدة عن المتقطعة. المؤثرات البصرية الغنية ومشاهد WebGL والحركة القائمة على الفيزياء تبدو مذهلة على حاسوب محمول راقٍ وتحوّل هاتفاً اقتصادياً إلى عرض شرائح. الحل ليس إزالتها، بل تقديمها بشكل مشروط.
- لا تشغّل WebGL ثقيلاً إلا حين يكون هناك GPU حقيقي. قبل تركيب مشهد ثلاثي الأبعاد باهظ، نكتشف سياق الرسم ونتحقق من مُحرّك الرسم المُبلَّغ عنه. على مُحرّك رسم برمجي أو جهاز يفشل في فحص قدرة سريع، نتراجع إلى صورة ثابتة أو نسخة CSS خفيفة بدلاً من حلقة WebGL كاملة.
- احترم المستخدم. احترم استعلام الوسائط
prefers-reduced-motionوتجاوز الحركة غير الأساسية لمن يطلب ذلك. تجاوز أيضاً المؤثرات الثقيلة حين يُبلّغ الجهاز عن عدد قليل من أنوية CPU أو حين يكون تلميح Save Data مفعّلاً. - انقل الحركة إلى CSS حيثما استطعت. حركات التحويل والشفافية في CSS تعمل على الـ compositor thread وتكلفتها زهيدة. مؤثر عند التمرير فوقه، تلاشٍ تدريجي، انزلاق خفيف: هذه من اختصاص CSS، لا مكتبة حركة JavaScript تعمل على الـ main thread.
- خفّف من وتيرة حلقة الرسم لديك. إذا اضطررت إلى تشغيل حلقة إطارات حركة، فحدّد سقفاً لمعدل الإطارات، وأوقفها تماماً حين يخرج العنصر عن مجال الرؤية بالتمرير أو حين تُخفى علامة التبويب. حلقة تعيد الرسم بأقصى سرعة لأجل canvas خارج الشاشة هي هدر محض يظهر كـ INP سيئ.
- لا تحمّل المكتبة الثقيلة إلا حين يكون المؤثر مرئياً فعلاً. استخدم intersection observer كي يُنزَّل bundle الخاص بـ WebGL أو الحركة حين يمرّر المستخدم قريباً منه، لا عند التحميل الأولي.
التحميل المؤجل والتخزين المؤقت وشبكة CDN
الطبقة الأخيرة تتعلق بعدم أداء العمل مرتين وعدم التقديم من مكان بعيد.
- حمّل بشكل مؤجل المحتوى الواقع أسفل حد الطي: الصور والـ iframes والتضمينات والمكوّنات الثقيلة. يوفّر المتصفح
loading="lazy"أصلياً للصور والـ iframes، ويغطّي intersection observer كل ما عدا ذلك. - خزّن مؤقتاً بقوة. الأصول الثابتة ذات أسماء الملفات المُهشّرة بالمحتوى يمكن تخزينها مؤقتاً لمدة عام، لأن أي تغيير في الملف يغيّر اسم الملف. اضبط ترويسات
Cache-Controlطويلة لتلك الأصول وأقصر للـ HTML. - استخدم شبكة CDN. تقديم الأصول من موقع حافة (edge) قريب من مستخدمك يقلّص زمن الاستجابة مباشرة، وهو ما يساعد LCP. كما تمتص شبكة CDN موجات حركة المرور المفاجئة وتخفف الحمل عن خادم المصدر لديك.
- اضغط كل شيء. Brotli للأصول النصية يتفوق على gzip، وينبغي أن يكون مفعّلاً افتراضياً على مستوى الخادم أو شبكة CDN.
- قلّل زمن استجابة الخادم. أول بايت بطيء يسمّم كل مؤشر لاحق. خزّن الصفحات المُصيَّرة مؤقتاً حيثما أمكن، وأبقِ عمل قاعدة البيانات خارج المسار الحرج. حين نصمم واجهات API خلف هذه الصفحات نحسّن الأداء لأجل هذا بالضبط، وهو موضوع نتعمق فيه في تصميم واجهات API يحبها المطورون.
قائمة تحقق الأداء
هذه هي القائمة المرقّمة التي نمرّ عليها قبل الإطلاق.
- أكّد عنصر LCP (عادةً الصورة الرئيسية أو العنوان) وامنحه تحميلاً ذا أولوية.
- قدّم AVIF أو WebP، مضبوط الحجم بشكل متجاوب باستخدام
srcsetوsizes. - حدّد أبعاداً صريحة أو
aspect-ratioعلى كل صورة وتضمين وسائط للقضاء على تزحزح التخطيط. - حمّل بشكل مؤجل كل صورة وiframe ومكوّن ثقيل أسفل حد الطي.
- استضف الخطوط ذاتياً، واقتصر على مجموعة جزئية منها (subset)، وحمّل مسبقاً الملفات الحرجة، واستخدم
font-display: swap. - دقّق في bundle الخاص بـ JavaScript واحذف التبعيات الثقيلة أو استبدلها.
- قسّم الشيفرة حسب المسار وحمّل بشكل مؤجل المكوّنات غير اللازمة عند الرسم الأول.
- أجّل سكربتات التحليلات والدردشة والتسويق حتى تصبح الصفحة تفاعلية.
- جزّئ أي مهمة على الـ main thread تتجاوز 50 ميلي ثانية وأعِد التحكم بين الأجزاء.
- فعّل WebGL فقط بعد التحقق من وجود GPU حقيقي، مع بديل احتياطي ثابت للأجهزة الضعيفة.
- انقل الحركات إلى تحويلات وشفافية CSS، واحترم
prefers-reduced-motion. - خفّف حلقات الرسم وأوقفها حين تكون خارج الشاشة أو حين تُخفى علامة التبويب.
- اضبط ترويسات تخزين مؤقت طويلة على الأصول الثابتة المُهشّرة وأقصر على الـ HTML.
- قدّم عبر شبكة CDN مع تفعيل ضغط Brotli.
- قِس بأدوات مخبرية (Lighthouse وTBT) أثناء التطوير، ثم تحقق ببيانات ميدانية (LCP وINP وCLS الحقيقية) بعد الإطلاق.
هذه النقطة الأخيرة هي ما يتخطاه الناس. تخبرك النتائج المخبرية بمكان المشكلات، لكن البيانات الميدانية وحدها تخبرك بما يعيشه مستخدموك الحقيقيون على أجهزتهم وشبكاتهم الحقيقية. نبني للمختبر ونتحقق في الميدان.
السرعة قرار تصميمي تتخذه عن قصد، مراراً وتكراراً، في كل طبقة. افعله جيداً وستعتني المؤشرات بنفسها، لأنها ليست سوى قياسات لموقع يحترم الشخص الذي يستخدمه.
إذا كان موقعك يبدو بطيئاً ولست متأكداً أين يذهب الوقت، فهذا بالضبط نوع المشكلات التي نحبها. ألقِ نظرة على خدماتنا أو تواصل معنا وسنساعدك على بناء شيء سريع.
جاهز للبناء مع Innovation T؟
سواء كان الأمر يتعلق بالأمن أو النمو أو الهندسة، يمكن لفريقنا مساعدتك على تنفيذه بإتقان.