في عالم يتسابق فيه المطورون لتحسين أداء الويب، تظل Core Web Vitals هي المعيار الذهبي. لكن هل ما زلنا نستخدمها بالطريقة الصحيحة؟ فكك معنا كيف تغيرت هذه المقاييس في 2025، وما هي الفخاخ التي يقع فيها حتى المحترفون.
في عام 2023، كانت Core Web Vitals مجرد ثلاثة أرقام بسيطة: Largest Contentful Paint (LCP)، First Input Delay (FID)، وCumulative Layout Shift (CLS). اليوم، في 2025، أصبحت هذه المقاييس أكثر تعقيداً ودقة، لكنها أيضاً أكثر إرباكاً. الشركات الكبرى مثل جوجل وأمازون ما زالت تعتمد عليها لتحديد ترتيب الصفحات وأدائها، لكن الكثير من المطورين ما زالوا يقيسونها بطريقة سطحية، وكأنهم يقيسون حرارة الفرن دون معرفة ما إذا كان الطعام سيحترق أم لا. الحقيقة هي أن Core Web Vitals لم تعد مجرد أرقام تُعرض في تقرير Lighthouse؛ إنها نافذة على كيفية تفاعل المستخدم الحقيقي مع تطبيقك، خلف الكواليس، في الذاكرة والمعالج.
في تجربتي مع فرق تطوير في شركات ناشئة ومنصات كبيرة، وجدت أن معظم المطورين يركزون على تحسين LCP دون فهم أن المشكلة الحقيقية قد تكون في الـ Render Blocking Resources أو حتى في كيفية تحميل الخطوط. مثلاً، في مشروع لشركة تجارة إلكترونية، اكتشفنا أن LCP كان يتأخر بسبب خط مخصص يُحمل من سيرفر خارجي، وليس بسبب الصور أو الجافاسكريبت. الحل لم يكن في ضغط الصور، بل في استخدام font-display: swap وتحميل الخط بشكل غير متزامن. هذا النوع من التفاصيل هو ما يميز المطور الذي يفهم الأداء حقاً عن الذي يتبع قوائم التحسين العادية.
Largest Contentful Paint هو المقياس الذي يقيس متى يظهر أكبر عنصر مرئي في الصفحة للمستخدم. في السابق، كان التركيز على الصور والنصوص الكبيرة، لكن في 2025، أصبحت العناصر الديناميكية مثل الـ Web Components والرسوميات المتحركة هي التحدي الجديد. المشكلة الأكبر هي أن الكثير من المطورين ما زالوا يعتقدون أن تحسين LCP يعني فقط ضغط الصور أو استخدام CDN، بينما الحقيقة هي أن الـ Critical Rendering Path هو ما يجب التركيز عليه. مثلاً، إذا كان لديك عنصر LCP هو صورة، لكن الـ CSS الخاص بها يُحمل بشكل متزامن، فإن المتصفح سيعلق حتى ينتهي تحميل الـ CSS، وهذا يعني أن LCP سيتأخر حتى لو كانت الصورة جاهزة.
في مشروع لشركة إعلامية، واجهنا مشكلة غريبة: LCP كان جيداً على الهواتف الجديدة، لكنه كان سيئاً جداً على الأجهزة القديمة. بعد التحقيق، اكتشفنا أن المشكلة لم تكن في الصورة نفسها، بل في كيفية معالجة المتصفح للـ Layout بعد تحميل الصورة. الأجهزة القديمة كانت تستغرق وقتاً أطول في حساب الـ Layout بسبب تعقيد الـ DOM. الحل كان في تبسيط الـ DOM وتقليل عدد العناصر المتداخلة، وليس في تحسين الصورة. هذا يوضح أن LCP ليس مجرد مقياس لعنصر واحد، بل هو نتيجة لتفاعل معقد بين المتصفح والـ CPU والذاكرة.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LCP Optimization Example</title>
<!-- Preload critical resources -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="hero-image.jpg" as="image">
<style>
/* Use font-display: swap to avoid blocking */
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2');
font-display: swap;
}
body {
font-family: 'CustomFont', sans-serif;
margin: 0;
}
/* Avoid layout shifts */
.hero {
width: 100%;
height: 500px;
background-image: url('hero-image.jpg');
background-size: cover;
}
</style>
</head>
<body>
<div class="hero"></div>
<!-- Load non-critical JS asynchronously -->
src="non-critical.js" defer></script>
</body>
</html>في مارس 2024، أعلنت جوجل عن استبدال First Input Delay (FID) بـ Interaction to Next Paint (INP)، وهو مقياس أكثر دقة لقياس استجابة الصفحة لتفاعلات المستخدم. الفرق الرئيسي هو أن FID كان يقيس فقط التأخير الأولي للاستجابة، بينما INP يقيس الوقت الكلي من التفاعل حتى ظهور النتيجة على الشاشة. هذا التغيير لم يكن مجرد تعديل بسيط؛ إنه يعكس حقيقة أن المستخدمين لا يهتمون فقط ببدء الاستجابة، بل يهتمون أيضاً بمدى سرعة رؤيتهم للتغيير.
في أحد المشاريع التي عملت عليها، كان لدينا تطبيق ويب معقد يعتمد على React وRedux. FID كان جيداً جداً (أقل من 100 مللي ثانية)، لكن المستخدمين كانوا يشتكون من بطء الاستجابة عند النقر على الأزرار. بعد تحليل INP، اكتشفنا أن المشكلة كانت في الـ Event Loop. عندما ينقر المستخدم على زر، كان الـ Event Handler يستدعي دالة تستغرق 300 مللي ثانية لمعالجة البيانات، وخلال هذا الوقت، كان الـ Main Thread مشغولاً ولا يستطيع معالجة أي تفاعلات أخرى. الحل كان في تقسيم المهمة إلى أجزاء أصغر باستخدام `setTimeout` أو `requestIdleCallback`، مما يسمح للمتصفح بمعالجة التفاعلات الأخرى بين الأجزاء.
// مثال على تقسيم مهمة طويلة لتحسين INP
function processLargeData(data, callback) {
const chunkSize = 100;
let index = 0;
function processChunk() {
const endIndex = Math.min(index + chunkSize, data.length);
for (; index < endIndex; index++) {
// معالجة جزء من البيانات
if (data[index].value > 100) {
callback(data[index]);
}
}
if (index < data.length) {
// السماح للمتصفح بمعالجة التفاعلات الأخرى
setTimeout(processChunk, 0);
}
}
processChunk();
}
// استخدام المثال
const data = Array.from({ length: 10000 }, (_, i) => ({ value: i }));
processLargeData(data, (item) => {
console.log('Processed:', item);
});تطبيقات الـ SPA مثل تلك المبنية باستخدام React أو Angular أو Vue تواجه تحديات فريدة مع INP. السبب هو أن هذه التطبيقات تعتمد على تحديث الـ DOM بشكل ديناميكي، وغالباً ما تستخدم مكتبات إدارة الحالة مثل Redux أو Vuex، والتي يمكن أن تؤدي إلى مهام طويلة في الـ Main Thread. مثلاً، في تطبيق React، إذا كان لديك مكون يستدعي `useEffect` عند تحميله، وكان هذا الـ `useEffect` يقوم بمعالجة بيانات كبيرة، فإن الـ Main Thread سيتعطل حتى تنتهي المعالجة، مما يؤدي إلى تأخير في استجابة الصفحة للتفاعلات الأخرى.
في مشروع لشركة SaaS، كان لدينا تطبيق React يعرض جداول بيانات كبيرة. عند تحميل الصفحة، كان الـ INP سيئاً جداً لأن المكون الرئيسي كان يقوم بمعالجة البيانات في `useEffect` دون تقسيمها. الحل كان في استخدام مكتبة مثل `react-window` لعرض البيانات بشكل مجزأ، بالإضافة إلى تقسيم عملية المعالجة باستخدام `requestIdleCallback`. النتيجة كانت تحسناً كبيراً في INP، حيث انخفض من 500 مللي ثانية إلى أقل من 200 مللي ثانية.
Cumulative Layout Shift هو المقياس الذي يقيس مدى استقرار الصفحة أثناء تحميلها. في عام 2025، ما زال هذا المقياس هو الأكثر إزعاجاً للمطورين، ليس لأنه صعب الفهم، بل لأنه يعتمد على تفاصيل صغيرة جداً قد لا تكون واضحة. مثلاً، في مشروع لشركة إعلانات، كان لدينا مشكلة مع CLS بسبب إعلانات يتم تحميلها بشكل ديناميكي بعد تحميل الصفحة. حتى بعد استخدام `aspect-ratio` و`min-height`، كان هناك shift بسيط يحدث لأن الإعلانات كانت تُحمل من مصادر خارجية ولا يمكن التحكم في حجمها بدقة.
الحقيقة هي أن CLS لا يتعلق فقط بالعناصر التي تتحرك، بل يتعلق أيضاً بالعناصر التي تظهر أو تختفي بعد تحميل الصفحة. مثلاً، إذا كان لديك زر يظهر بعد تحميل بيانات من API، فإن هذا الزر سيؤدي إلى shift إذا لم يكن هناك مساحة محجوزة له مسبقاً. الحل ليس فقط في استخدام `min-height`، بل أيضاً في التفكير في كيفية تحميل العناصر الديناميكية. في أحد المشاريع، استخدمنا `content-visibility: auto` لعزل أجزاء من الصفحة التي لا تكون مرئية فوراً، مما قلل من CLS بشكل كبير.
/* مثال على تحسين CLS باستخدام aspect-ratio وcontent-visibility */
.ad-container {
/* حجز مساحة مسبقة للإعلان */
aspect-ratio: 16 / 9;
min-height: 250px;
background-color: #f0f0f0;
}
.dynamic-content {
/* تحسين أداء العناصر الديناميكية */
content-visibility: auto;
contain-intrinsic-size: 1000px;
}
/* تجنب تحميل الخطوط بشكل متأخر */
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2');
font-display: block;
/* استخدام font-display: block لتجنب shift عند تحميل الخط */
}رغم كل التغييرات، هناك أشياء بقيت ثابتة في Core Web Vitals. أولاً، التركيز على تجربة المستخدم الحقيقية، وليس فقط على الأرقام في تقارير Lighthouse. ثانياً، أهمية قياس الأداء في ظروف حقيقية، وليس فقط في بيئات التطوير. ثالثاً، أن تحسين الأداء ليس مجرد مهمة للمطورين، بل هو مسؤولية مشتركة بين الفرق الأمامية والخلفية وحتى فرق التصميم. مثلاً، في مشروع لشركة سفر، كان لدينا مشكلة مع LCP بسبب صور عالية الدقة تُرسل إلى جميع الأجهزة، بما في ذلك الهواتف القديمة. الحل لم يكن فقط في تحسين الصور، بل أيضاً في التعاون مع فريق التصميم لتوفير صور بديلة بناءً على حجم الشاشة.
أيضاً، بقيت أهمية مراقبة الأداء بشكل مستمر. Core Web Vitals ليست مجرد أرقام تُقاس مرة واحدة وتُنسى، بل هي مؤشرات يجب مراقبتها باستمرار، خاصة بعد كل تحديث رئيسي للتطبيق. في تجربتي، أفضل الأدوات لمراقبة الأداء هي تلك التي توفر بيانات حقيقية من المستخدمين، مثل Google Analytics وSentry، وليس فقط تقارير Lighthouse في بيئات التطوير.
إذا كان هناك شيء واحد يجب أن تأخذه من هذا المقال، فهو هذا: لا تعامل Core Web Vitals كأرقام يجب تحسينها، بل تعامل معها كمؤشرات على كيفية تفاعل المستخدم الحقيقي مع تطبيقك. إذا كان LCP سيئاً، لا تكتفِ بضغط الصور؛ اسأل نفسك لماذا يتأخر ظهور العنصر الرئيسي. إذا كان INP سيئاً، لا تكتفِ بتقسيم المهام؛ اسأل نفسك لماذا يتعطل الـ Main Thread. وإذا كان CLS سيئاً، لا تكتفِ بحجز مساحة للعناصر الديناميكية؛ اسأل نفسك لماذا يتغير تخطيط الصفحة بعد تحميلها. الأداء ليس مجرد أرقام، بل هو تجربة المستخدم الحقيقية، خلف الكواليس، في الذاكرة والمعالج.
ابدأ اليوم بقياس Core Web Vitals في ظروف حقيقية، وليس فقط في بيئات التطوير. استخدم أدوات مثل Sentry لمراقبة الأداء بعد كل تحديث، وتأكد من أن فريقك يفهم أن الأداء ليس مسؤولية المطورين فقط، بل هو مسؤولية الجميع. وإذا كنت تريد نصيحة عملية واحدة: قم بتشغيل Lighthouse في وضع Device Emulation على شبكة بطيئة وجهاز قديم، وشاهد كيف يتصرف تطبيقك. هذا هو الاختبار الحقيقي الذي سيكشف لك المشاكل التي لا تظهر في التقارير العادية.