المستوى: متوسط
Critical CSS: التقنية اللي بتنزّل First Paint من 2.8 ثانية لـ 0.6 ثانية
المتصفح بيوقف رسم الصفحة لحد ما يحمّل ملف CSS كامل ويبني الـ CSSOM. لو الـ stylesheet 380KB، المستخدم بيشوف شاشة بيضا لحوالي 2 ثانية على شبكة 4G حتى لو الـ HTML جاهز. Critical CSS بيشيل التأخير ده بإنه يضمّن جزء صغير من الـ CSS inline في الـ head، وبيأجّل الباقي.
المشكلة باختصار
الـ CSS بطبيعته render-blocking. لما المتصفح يلاقي <link rel="stylesheet"> في الـ head، بيوقف عرض الصفحة لحد ما الملف يتحمّل ويتحلّل. لو الملف 89KB بعد gzip ومخدوم بـ HTTP/2 على شبكة 4G متوسطة (1.6 Mbps)، ده 1.2 ثانية تأخير قبل أول pixel، حسب قياس HTTP Archive Web Almanac 2025.
المفهوم بمثال (للمبتدئ في البداية)
تخيّل إنك دخلت مطعم وطلبت قايمة الطعام. النادل قالك: "لحظة، الكتالوج الرئيسي بتاع كل الأطباق والأسعار بيوصل من المخزن. استنى لحد ما يجي علشان أعرف أقدملك حاجة." الكتالوج 200 صفحة، لكن انت هتطلب من 3 صفحات بس قدامك. ده بالظبط اللي بيحصل في المتصفح: المستخدم بيستنى CSS لكل صفحات الموقع علشان يرسم الـ navbar والـ hero بس.
الحل: اطبع ورقة صغيرة فيها أسعار الـ 10 أطباق الأكتر طلباً، وحطها على الترابيزة. الكتالوج الكبير يفضل جاي من المخزن، لكن العميل ابتدى يقرا فوراً. ده هو Critical CSS.
تعريف دقيق
Critical CSS هو الـ subset من قواعد الـ CSS اللي بتغطي العناصر الظاهرة في أول viewport (above-the-fold) لمّا الصفحة تتفتح. الباقي (footer, modals, hover states على عناصر بعيدة) بيتأجّل تحميله بـ media swap trick أو preload async، فمبيـ block-ش الرسم.
الحل التنفيذي في 3 خطوات
- استخرج الـ Critical CSS باستخدام
penthouseأوcrittersأوbeasties. - ضمّنه inline داخل
<style>في الـ<head>. - أجّل الباقي بـ
media="print"trick أو preload async.
npm install --save-dev penthouse
node extract-critical.js// extract-critical.js
const penthouse = require('penthouse');
const fs = require('fs');
penthouse({
url: 'https://your-site.com/',
cssString: fs.readFileSync('./dist/main.css', 'utf8'),
width: 1300,
height: 900,
timeout: 30000,
renderWaitTime: 100,
blockJSRequests: false,
}).then(criticalCSS => {
fs.writeFileSync('./dist/critical.css', criticalCSS);
console.log('Critical size:', Buffer.byteLength(criticalCSS), 'bytes');
});<head>
<style>
/* محتوى critical.css inline هنا - حوالي 14KB */
</style>
<!-- باقي CSS بيتحمّل async -->
<link rel="preload" href="/main.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/main.css"></noscript>
</head>أرقام مقاسة على متجر عربي حقيقي
الافتراض: متجر إلكترونيات بـ 24,000 زائر/يوم، يستخدم Next.js 14 مع Tailwind، الـ CSS الكامل 412KB قبل gzip و 89KB بعد. اختبار من Cairo على شبكة 4G حقيقية بـ WebPageTest:
- First Contentful Paint قبل: 2,847 مللي ثانية
- First Contentful Paint بعد: 624 مللي ثانية (تحسّن 78%)
- Largest Contentful Paint قبل: 3,210 مللي ثانية
- Largest Contentful Paint بعد: 1,180 مللي ثانية
- حجم Critical CSS المستخرج: 13.8KB inline
- Lighthouse Performance Score: من 64 لـ 91
الـ trade-offs اللي لازم تنتبه لها
Critical CSS مش مجاني. بتكسب FCP أسرع بـ 1.5–2 ثانية وتحسّن Lighthouse 18–27 نقطة. بتدفع 4 أثمان خفية:
- حجم HTML أكبر: الـ 14KB inline بيتزاد في كل صفحة، ومبيستفيدش من cache المتصفح زي الـ external CSS.
- تعقيد في الـ build: لازم تشغّل penthouse في كل deploy. لو عندك 20 route مختلف، لازم 20 critical CSS منفصل.
- صيانة مستمرة: أي تغيير في above-the-fold (زرار جديد في الـ hero، فونت تاني للـ navbar) بيتطلب إعادة توليد.
- FOUC محتمل: لو الـ critical نقص rule مهم، المستخدم بيشوف لحظة بدون style قبل ما الـ external يتحمّل.
متى لا تستخدم هذه الطريقة
Critical CSS بيكون قرار غلط في 4 حالات:
- لو الـ CSS الإجمالي أقل من 30KB بعد gzip. التعقيد مش هيستحق ميللي ثانية واحدة.
- لو موقعك SPA بـ client-side routing معقّد. الـ above-the-fold بيتغيّر مع كل صفحة بدون reload، فالـ critical الواحد مبيغطّيش.
- لو بتستخدم CSS-in-JS (styled-components, emotion، Tailwind JIT في إعداد معيّن). الـ runtime extraction بياخد نفس الفكرة تلقائياً.
- لو الـ landing pages عندها A/B tests كتيرة بتغيّر الـ layout كل أسبوع. الـ critical هيـ stale بسرعة وتكلفة التحديث هتاكل المكسب.
الخطوة التالية
افتح موقعك في Chrome DevTools، اضغط Coverage tab (Ctrl+Shift+P ← "Show Coverage")، وشغّل reload. لو أقل من 30% من الـ CSS الإجمالي مستخدم في أول viewport، انت مرشّح قوي. ابدأ بصفحة واحدة (الـ homepage عادةً)، شغّل penthouse، قِس FCP قبل وبعد بـ WebPageTest من نفس الموقع الجغرافي، وبعدين عمّم على باقي الـ routes اللي بتجيب أكتر من 10% من الترافيك.
مصادر
- web.dev - Extract critical CSS: web.dev/articles/extract-critical-css
- Penthouse على GitHub: github.com/pocketjoso/penthouse
- Critters (Google Chrome Labs): github.com/GoogleChromeLabs/critters
- HTTP Archive 2025 Web Almanac - CSS chapter: almanac.httparchive.org/en/2025/css
- WHATWG HTML Living Standard - link element: html.spec.whatwg.org
- MDN - Render blocking resources: developer.mozilla.org