في 2025، لم تعد Core Web Vitals مجرد مقاييس لتحسين محركات البحث، بل أصبحت قضية وجودية لتجربة المستخدم. اكتشف كيف تغيرت هذه المقاييس خلف الكواليس، وما الذي بقي ثابتاً في عالم الأداء، ولماذا قد تكون الأرقام التي تراها في Lighthouse مجرد وهم.
في عام 2023، كان إرسال حزمة جافا سكريبت بحجم ٥٠٠ كيلوبايت يعتبر سيئاً. في 2025، نفس الحزمة أصبحت كارثة حقيقية لا تُغتفر. المشكلة ليست في الحجم فقط، بل في ما يفعله هذا الكود بالـ Event Loop وبذاكرة المتصفح. عندما يتجمد المتصفح لثانية كاملة لأن سكربت واحد يحجز الـ Main Thread، فإن LCP وINP وCLS تتدهور جميعاً في آن واحد. والأمر الأكثر إيلاماً هو أن معظم المطورين لا يدركون أن الـ 90 نقطة التي يحصلون عليها في Lighthouse هي مجرد وهم مؤقت يختفي بمجرد أن يفتح المستخدم الحقيقي الصفحة على هاتف متوسط الأداء.
الـ Core Web Vitals لم تعد مجرد ثلاثة أرقام في تقرير PageSpeed Insights. لقد أصبحت لغة مشتركة بين فرق التطوير وفرق التسويق وفرق المنتج، بل وحتى فرق المبيعات. عندما يقول مدير المنتج إن الصفحة يجب أن تكون "سريعة"، فإن المطور يفهم الآن أن هذا يعني LCP تحت 1.5 ثانية، وINP تحت 100 مللي ثانية، وCLS تحت 0.1. لكن الحقيقة التي لا يريد أحد الاعتراف بها هي أن هذه الأرقام أصبحت أصعب بكثير في تحقيقها مع تعقيد التطبيقات الحديثة، خاصة مع اعتمادنا المتزايد على مكتبات مثل React وNext.js التي تضيف طبقات من التجريد فوق الـ DOM الحقيقي.
LCP أو Largest Contentful Paint مازال هو المقياس الأكثر إزعاجاً في 2025، ليس لأنه صعب القياس، بل لأنه يعتمد على عوامل خارج سيطرة المطور بشكل مباشر. في الماضي، كنا نركز على تحسين وقت تحميل الصور أو تقليل حجم CSS. اليوم، المشكلة الحقيقية تكمن في ما يحدث قبل أن يبدأ المتصفح حتى في تحميل الصفحة. عندما يرسل السيرفر استجابة HTML بطيئة بسبب قاعدة بيانات غير مُحسّنة أو API خارجي معطل، فإن LCP يتدهور قبل أن يبدأ أي كود جافا سكريبت في التنفيذ. وهذا ما يجعل تحسين LCP أشبه بلعبة شطرنج معقدة، حيث يجب التفكير في كل خطوة من الـ Network Waterfall، بدءاً من وقت الاستجابة الأولي للسيرفر (TTFB) وصولاً إلى وقت عرض العنصر الأكبر في الصفحة.
في تجربتي مع أحد عملاء التجارة الإلكترونية، اكتشفنا أن LCP كان يتأخر بمقدار ثانية كاملة بسبب خط واحد في ملف nginx. كان السيرفر يرسل Headers إضافية غير ضرورية مع كل استجابة، مما كان يضيف 200 مللي ثانية إلى TTFB. وعندما قمنا بإزالة هذه الـ Headers، تحسن LCP من 2.8 ثانية إلى 1.6 ثانية دون أي تغيير في الكود الأمامي. هذا يثبت أن تحسين الأداء لم يعد مقتصراً على فريق الـ Frontend فقط، بل أصبح مسؤولية مشتركة بين الـ Backend وDevOps وحتى فرق البنية التحتية. المشكلة الأكبر هي أن معظم الأدوات مثل Lighthouse لا تخبرك بأن المشكلة قد تكون في الـ Server Response، بل تركز فقط على ما يحدث في المتصفح بعد استلام الـ HTML.
# قبل التحسين - LCP = 2.8s
server {
listen 443 ssl;
server_name example.com;
add_header X-Frame-Options "DENY";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'";
# هذه الـ Headers كانت تضيف 200ms إلى TTFB
}
# بعد التحسين - LCP = 1.6s
server {
listen 443 ssl;
server_name example.com;
# تم نقل الـ Headers الأمنية إلى CDN
# أو تم إعدادها على مستوى أعلى في بنية nginx
}في مارس 2024، أعلنت جوجل أن INP (Interaction to Next Paint) سيحل محل FID (First Input Delay) كمقياس رسمي في Core Web Vitals. هذا التغيير لم يكن مجرد استبدال مصطلح بآخر، بل كان اعترافاً بأن مشكلة التفاعل مع الصفحة أصبحت أكثر تعقيداً من مجرد قياس التأخير الأولي. INP يقيس كل تفاعل للمستخدم مع الصفحة طوال فترة الزيارة، وليس فقط التفاعل الأول. وهذا يعني أن أي كود جافا سكريبت ثقيل أو أي عملية I/O Bound في الـ Event Loop يمكن أن تدمر تجربتك بالكامل، حتى لو كانت الصفحة تبدو سريعة في البداية.
المشكلة الحقيقية مع INP هي أنه يكشف عن الفجوة بين ما نراه في بيئات التطوير وما يختبره المستخدمون الحقيقيون. في بيئة التطوير المحلية، قد يكون الـ Event Loop نظيفاً وخالياً من المهام الثقيلة، لكن في الواقع، عندما يفتح المستخدم الصفحة على هاتف قديم، فإن أي عملية حسابية معقدة أو أي طلب API بطيء يمكن أن يجعل الصفحة تتجمد تماماً. لقد رأيت هذا يحدث مع تطبيق React يستخدم مكتبة الرسوم البيانية Chart.js. كان التطبيق يعمل بشكل مثالي على أجهزة المطورين، لكن عندما فتحناه على هاتف Samsung Galaxy A12، كانت الصفحة تتجمد تماماً عند محاولة التمرير بسبب إعادة رسم الرسوم البيانية في كل مرة. الحل؟ استخدام Web Workers لفصل العمليات الثقيلة عن الـ Main Thread، وتقليل عدد مرات إعادة الرسم باستخدام تقنيات مثل Memoization وDebouncing.
// مشكلة INP: الرسوم البيانية تعطل الـ Event Loop
import { useEffect, useRef } from 'react';
import Chart from 'chart.js/auto';
function SalesChart({ data }) {
const chartRef = useRef(null);
const chartInstance = useRef(null);
useEffect(() => {
if (chartRef.current && data) {
// هذا الكود يعمل في كل مرة تتغير فيها البيانات
// مما يسبب إعادة رسم كاملة للرسوم البيانية
// ويؤدي إلى تجميد الصفحة عند التفاعل
if (chartInstance.current) {
chartInstance.current.destroy();
}
chartInstance.current = new Chart(chartRef.current, {
type: 'line',
data: data,
});
}
}, [data]);
return <canvas ref={chartRef} />;
}
// الحل: استخدام Web Worker لتقليل الحمل على الـ Main Thread
// worker.js
self. function(e) {
const { data } = e.data;
// معالجة البيانات الثقيلة هنا
const processedData = processChartData(data);
postMessage(processedData);
};
function processChartData(data) {
// منطق معالجة البيانات...
return data;
}
// في المكون React
function SalesChartOptimized({ data }) {
const chartRef = useRef(null);
const chartInstance = useRef(null);
const workerRef = useRef(null);
useEffect(() => {
workerRef.current = new Worker('worker.js');
workerRef.current.onmessage = (e) => {
const processedData = e.data;
if (chartInstance.current) {
chartInstance.current.data = processedData;
chartInstance.current.update();
} else {
chartInstance.current = new Chart(chartRef.current, {
type: 'line',
data: processedData,
});
}
};
return () => {
workerRef.current.terminate();
};
}, []);
useEffect(() => {
if (workerRef.current && data) {
workerRef.current.postMessage({ data });
}
}, [data]);
return <canvas ref={chartRef} />;
}الكثير من المطورين يعتقدون أن استخدام Debouncing يكفي لحل مشاكل INP. الحقيقة هي أن Debouncing مفيد فقط للتفاعلات المتكررة مثل التمرير أو تغيير حجم النافذة، لكنه لا يحل المشكلة الأساسية وهي تحميل الـ Main Thread. في المثال السابق، حتى لو استخدمنا Debouncing لتأخير إعادة رسم الرسوم البيانية، فإن العملية نفسها ستظل تحدث في الـ Main Thread، مما سيؤدي إلى تجميد الصفحة عند تنفيذها. هذا هو السبب في أن استخدام Web Workers أصبح ضرورياً في 2025، خاصة للتطبيقات التي تعتمد على معالجة بيانات ثقيلة أو رسوم بيانية معقدة.
CLS أو Cumulative Layout Shift مازال هو المقياس الأكثر إحباطاً للمطورين، ليس لأنه صعب الفهم، بل لأنه غالباً ما يكون خارج سيطرة فريق الـ Frontend تماماً. في الماضي، كنا نركز على إضافة أبعاد ثابتة للصور والإطارات، لكن في 2025، أصبحت المشكلة أكثر تعقيداً بسبب اعتمادنا المتزايد على المحتوى الديناميكي والإعلانات والتوصيات الشخصية. عندما يتغير تخطيط الصفحة بعد تحميلها بسبب تحميل إعلان متأخر أو بسبب ظهور عنصر جديد من API، فإن CLS يتدهور، حتى لو كانت الصفحة تبدو مستقرة للمطور.
لقد واجهت هذه المشكلة مع موقع إخباري كبير يستخدم نظام توصيات مخصص. كان الموقع يعرض مقالات ذات صلة بعد تحميل الصفحة بمقدار ثانيتين، مما كان يسبب انزياحاً كبيراً في المحتوى ويؤدي إلى CLS يبلغ 0.3. الحل لم يكن تقنياً بحتاً، بل تطلب تعاوناً بين فريق الـ Frontend وفريق الإعلانات وفريق المحتوى. قمنا بتخصيص مساحة ثابتة لعناصر التوصيات والإعلانات باستخدام CSS Grid، حتى لو كانت هذه المساحات فارغة في البداية. كما أضفنا تحميلاً تدريجياً للمحتوى باستخدام Intersection Observer، بحيث لا يتم تحميل العناصر الجديدة إلا عندما تصبح قريبة من منطقة العرض. النتيجة؟ انخفض CLS من 0.3 إلى 0.05 دون أي تأثير على إيرادات الإعلانات.
/* حل CLS: تخصيص مساحة ثابتة للعناصر الديناميكية */
.article-container {
display: grid;
grid-template-areas:
"header"
"content"
"ads"
"recommendations"
"footer";
grid-template-rows: auto 1fr auto auto auto;
}
.ads-slot, .recommendations-slot {
/* تخصيص مساحة ثابتة حتى لو كانت العناصر غير محملة */
min-height: 250px;
background: #f5f5f5;
}
/* تحميل المحتوى عند الاقتراب من منطقة العرض */
.recommendations-slot {
content-visibility: auto;
contain-intrinsic-size: 250px;
}الكثير من المطورين يعتقدون أن استخدام خاصية aspect-ratio في CSS كافية لحل مشاكل CLS. الحقيقة هي أن هذه الخاصية مفيدة فقط للعناصر التي لها نسبة عرض إلى ارتفاع ثابتة ومعروفة مسبقاً، مثل الصور والفيديوهات. لكنها لا تحل المشكلة مع المحتوى الديناميكي مثل الإعلانات أو توصيات المقالات، حيث قد يختلف ارتفاع المحتوى بشكل كبير. في هذه الحالات، يجب استخدام تقنيات أكثر تقدماً مثل تخصيص مساحة ثابتة باستخدام CSS Grid أو Flexbox، واستخدام Intersection Observer لتحميل المحتوى فقط عندما يصبح قريباً من منطقة العرض.
إذا قارنا Core Web Vitals في 2020 مع ما هي عليه في 2025، سنجد أن التغييرات ليست في المقاييس نفسها فقط، بل في كيفية قياسها وتأثيرها على تجربة المستخدم. في 2020، كان التركيز على تحسين وقت التحميل الأولي، وكان Lighthouse هو الأداة الرئيسية للقياس. في 2025، أصبح الأداء تجربة مستمرة طوال فترة زيارة المستخدم، وليس مجرد لحظة التحميل الأولى. هذا التغيير أدى إلى ظهور أدوات جديدة مثل Chrome User Experience Report (CrUX) وWeb Vitals Library التي تقيس الأداء في العالم الحقيقي، وليس فقط في بيئات الاختبار المحلية.
أحد أكبر التغييرات هو كيفية تعامل جوجل مع هذه المقاييس في ترتيب نتائج البحث. في الماضي، كانت Core Web Vitals مجرد عامل ثانوي في ترتيب الصفحات. اليوم، أصبحت هذه المقاييس جزءاً أساسياً من خوارزميات الترتيب، خاصة للمواقع التي تعتمد على المحتوى الديناميكي والتطبيقات الويب التقدمية (PWA). هذا يعني أن تحسين الأداء لم يعد مجرد مسألة تحسين تجربة المستخدم، بل أصبح ضرورة للبقاء في نتائج البحث الأولى. المشكلة هي أن الكثير من المواقع لا تزال تعتمد على أدوات مثل Lighthouse التي تعطي نتائج مثالية في بيئات الاختبار، لكنها لا تعكس ما يختبره المستخدمون الحقيقيون على أجهزتهم المختلفة.
رغم كل التطورات في أدوات القياس والمقاييس نفسها، هناك أشياء أساسية لم تتغير في عالم أداء الويب. الأول هو أن الـ Main Thread مازال هو نقطة الضعف الرئيسية في أي تطبيق ويب. سواء كنا نتحدث عن LCP أو INP أو CLS، فإن أي كود ثقيل أو أي عملية I/O Bound في الـ Main Thread ستدمر تجربة المستخدم. الثاني هو أن تحسين الأداء مازال يتطلب تفكيراً شاملاً، وليس مجرد تحسينات جزئية. في الماضي، كنا نركز على تحسين وقت تحميل الصور. اليوم، يجب أن نفكر في كل شيء من وقت استجابة السيرفر إلى كيفية تنفيذ جافا سكريبت في المتصفح.
الشيء الثالث الذي بقي ثابتاً هو أن معظم مشاكل الأداء يمكن حلها بتقنيات بسيطة إذا تم تطبيقها بشكل صحيح. على سبيل المثال، استخدام تقنيات مثل Code Splitting وLazy Loading مازال فعالاً في تحسين LCP، حتى في 2025. المشكلة هي أن الكثير من المطورين إما لا يعرفون هذه التقنيات أو يطبقونها بشكل خاطئ. لقد رأيت تطبيقات React تستخدم React.lazy لتحميل المكونات، لكنها لا تستخدم Suspense مع fallback مناسب، مما يؤدي إلى ظهور محتوى فارغ بدلاً من تحميل تدريجي. هذا النوع من الأخطاء البسيطة يمكن أن يدمر تجربة المستخدم تماماً، حتى لو كان الكود نظيفاً ومُحسّناً من الناحية النظرية.
// تطبيق خاطئ لـ Lazy Loading
const LazyComp React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<div>
{/* بدون Suspense، سيظهر خطأ إذا فشل التحميل */}
<LazyComponent />
</div>
);
}
// التطبيق الصحيح
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<React.Suspense fallback={<div>جاري التحميل...</div>}>
<LazyComponent />
</React.Suspense>
);
}في 2025، مازالت الذاكرة هي العدو الخفي الذي يدمر أداء التطبيقات دون أن يدرك المطورون ذلك. عندما نتحدث عن أداء الويب، نفكر عادة في وقت التنفيذ أو حجم الملفات، لكن الحقيقة هي أن تسرب الذاكرة (Memory Leak) يمكن أن يجعل تطبيقك يتجمد تماماً بعد دقائق من الاستخدام. لقد رأيت هذا يحدث مع تطبيق React يستخدم Context API بشكل مفرط. كان التطبيق يعمل بشكل مثالي في البداية، لكن بعد تصفح عدة صفحات، كان المتصفح يبدأ في التباطؤ تدريجياً حتى يتجمد تماماً. السبب؟ كان الـ Context يحتفظ بمراجع للمكونات القديمة التي لم تعد مستخدمة، مما كان يمنع الـ Garbage Collector من تحرير الذاكرة. الحل؟ استخدام useMemo وuseCallback بحذر، وتجنب الاحتفاظ بمراجع غير ضرورية في الحالة العامة للتطبيق.
إذا كنت تريد تحسين Core Web Vitals في 2025، فابدأ بقياس الأداء الحقيقي باستخدام أدوات مثل Chrome User Experience Report (CrUX) بدلاً من الاعتماد فقط على Lighthouse. ثم ركز على تحسين ثلاثة أشياء رئيسية: وقت استجابة السيرفر (TTFB)، ووقت تنفيذ جافا سكريبت في الـ Main Thread، واستقرار التخطيط (CLS). استخدم Web Workers لفصل العمليات الثقيلة عن الـ Main Thread، وقم بتخصيص مساحة ثابتة للعناصر الديناميكية لمنع انزياح المحتوى. وأخيراً، لا تنسَ أن معظم مشاكل الأداء يمكن حلها بتقنيات بسيطة إذا تم تطبيقها بشكل صحيح، لذا ابدأ بالأساسيات قبل الغوص في الحلول المعقدة.
الأداء في 2025 ليس مجرد مسألة تحسين أرقام في تقرير، بل هو مسألة بقاء. عندما يتجمد تطبيقك على هاتف متوسط الأداء، فإن المستخدم لن ينتظر حتى تنتهي عملية التحميل، بل سيغلق الصفحة وينتقل إلى منافسك. لذا فإن الاستثمار في الأداء ليس ترفاً، بل هو ضرورة للبقاء في المنافسة. ابدأ بقياس الأداء الحقيقي اليوم، ثم قم بتحسين كل جزء من رحلة المستخدم، بدءاً من وقت استجابة السيرفر وصولاً إلى آخر تفاعل في الصفحة. وتذكر دائماً: الأرقام التي تراها في Lighthouse هي مجرد بداية، أما ما يهم حقاً فهو ما يختبره المستخدمون الحقيقيون على أجهزتهم الحقيقية.