تحسين أداء CSS
تحسين أداء CSS
يؤثر CSS على كل من وقت التحميل والأداء أثناء التشغيل. يمكن أن يتسبب CSS غير المُحسّن في عرض بطيء للصفحة ورسوم متحركة متقطعة وإعادة رسم غير ضرورية. يغطي هذا الدرس تقنيات تحسين تسليم CSS وتقليل تكاليف العرض وتحسين الأداء المرئي من خلال ميزات CSS الحديثة وأفضل الممارسات.
CSS الحرج
أدرج CSS الحرج للمحتوى أعلى الصفحة مباشرة للقضاء على حظر العرض:
<style>
/* فقط الأنماط للمحتوى أعلى الصفحة */
.header { background: #333; padding: 1rem; }
.hero { min-height: 100vh; display: flex; }
.hero h1 { font-size: 3rem; color: #fff; }
</style>
<!-- تحميل CSS المتبقي بشكل غير متزامن -->
<link rel="preload" href="/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>
احتواء CSS
استخدم احتواء CSS للحد من نطاق التخطيط والرسم:
.card {
contain: layout style paint;
/* المتصفح يعلم أن التغييرات بالداخل لن تؤثر على الخارج */
}
/* احتواء صارم للأدوات المعزولة تمامًا */
.widget {
contain: strict;
/* يعادل: layout style paint size */
}
/* احتواء المحتوى للمحتوى الديناميكي */
.content-area {
contain: content;
/* يعادل: layout style paint */
}
/* مثال: تحسين قائمة */
.list-item {
contain: layout style;
/* التغييرات على عنصر واحد لا تؤدي إلى إعادة تدفق الآخرين */
}
خاصية content-visibility
.section {
content-visibility: auto;
contain-intrinsic-size: 0 500px; /* احتجاز المساحة */
}
/* مثال: مقال طويل مع أقسام */
<style>
.article-section {
content-visibility: auto;
contain-intrinsic-size: 0 400px;
}
</style>
<article>
<section class="article-section">...</section>
<section class="article-section">...</section>
<section class="article-section">...</section>
</article>
/* النتيجة: يتم عرض الأقسام المرئية فقط */
/* يمكن تقليل وقت العرض بنسبة 50-70٪ في الصفحات الطويلة */
خاصية will-change
ألمح للمتصفح بالتغييرات القادمة للتحسين:
.modal {
will-change: transform, opacity;
}
/* طبّق قبل التغيير، أزل بعده */
.element:hover {
will-change: transform;
}
.element:active {
transform: scale(1.1);
will-change: auto; /* إعادة التعيين بعد الرسوم المتحركة */
}
/* مثال JavaScript */
const element = document.querySelector('.animate');
element.addEventListener('mouseenter', () => {
element.style.willChange = 'transform';
});
element.addEventListener('animationend', () => {
element.style.willChange = 'auto';
});
تسريع GPU
استخدم transform و opacity للرسوم المتحركة السلسة:
.box {
transition: width 0.3s, height 0.3s, top 0.3s, left 0.3s;
}
.box:hover {
width: 200px;
height: 200px;
top: 50px;
left: 50px;
}
/* جيد: يستخدم تركيب GPU */
.box {
transition: transform 0.3s, opacity 0.3s;
}
.box:hover {
transform: scale(1.5) translate(25px, 25px);
opacity: 0.9;
}
/* فرض تسريع GPU مع translateZ */
.animated {
transform: translateZ(0); /* ينشئ طبقة تركيب جديدة */
backface-visibility: hidden; /* يمنع الوميض */
}
تقليل إعادة الرسم وإعادة التدفق
قلل من تذبذب التخطيط وإعادة الحسابات غير الضرورية:
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
const width = box.offsetWidth; // قراءة (تؤدي إلى إعادة تدفق)
box.style.width = width + 10 + 'px'; // كتابة (تؤدي إلى إعادة تدفق)
});
// جيد: تجميع القراءات والكتابات
const boxes = document.querySelectorAll('.box');
const widths = Array.from(boxes).map(box => box.offsetWidth);
boxes.forEach((box, i) => {
box.style.width = widths[i] + 10 + 'px';
});
// استخدم فئات CSS بدلاً من الأنماط المضمنة
// سيء: يفرض إعادة حساب النمط
element.style.width = '100px';
element.style.height = '100px';
element.style.background = 'red';
// جيد: تغيير فئة واحدة
element.classList.add('large-red-box');
// استخدم DocumentFragment لإدراجات DOM متعددة
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const div = document.createElement('div');
fragment.appendChild(div);
}
container.appendChild(fragment); // إعادة تدفق واحدة
أداء CSS-in-JS
حسّن توليد CSS في وقت التشغيل:
function Component({ color }) {
return (
<div style={{ backgroundColor: color, padding: '20px' }}>
Content
</div>
);
}
// جيد: استخراج الأنماط الثابتة
const staticStyles = { padding: '20px' };
function Component({ color }) {
return (
<div style={{ ...staticStyles, backgroundColor: color }}>
Content
</div>
);
}
// أفضل: استخدام فئات CSS مع متغيرات ديناميكية
const styles = `
.component {
padding: 20px;
background-color: var(--bg-color);
}
`;
function Component({ color }) {
return (
<div className="component" style={{ '--bg-color': color }}>
Content
</div>
);
}
إزالة CSS غير المستخدم
أزل الأنماط غير المستخدمة لتقليل حجم الحزمة:
module.exports = {
content: [
'./src/**/*.html',
'./src/**/*.js',
'./src/**/*.jsx',
],
css: ['./src/styles/**/*.css'],
output: './dist/styles/',
safelist: [
'active', 'open', 'visible', // فئات ديناميكية
/^modal-/, // أنماط regex
]
};
// إعداد Tailwind CSS purge
module.exports = {
purge: {
enabled: true,
content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
options: {
safelist: ['bg-red-500', 'text-center'],
}
},
};
// النتيجة: يمكن تقليل CSS من 500 كيلوبايت إلى 10-20 كيلوبايت
تحسين المحددات
body div.container ul li a.link { color: blue; }
/* المتصفح يقرأ من اليمين إلى اليسار، يفحص كل رابط */
/* جيد: محددات بسيطة ومحددة */
.nav-link { color: blue; }
/* سيء: محدد عالمي */
* { box-sizing: border-box; }
/* جيد: استهداف عناصر محددة */
html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }
/* استخدم BEM للخصوصية المسطحة */
.card { }
.card__header { }
.card__title { }
.card--featured { }
/* تجنب المحددات الزائفة المكلفة */
/* سيء */
:nth-child(n+1):nth-child(-n+10) { }
/* جيد */
.item:nth-child(-n+10) { }
استراتيجيات تحميل CSS
<style>/* CSS حرج */</style>
<link rel="preload" href="main.css" as="style" onload="this.rel='stylesheet'">
<!-- الاستراتيجية 2: استعلامات الوسائط للتحميل الشرطي -->
<link rel="stylesheet" href="print.css" media="print">
<link rel="stylesheet" href="mobile.css" media="(max-width: 768px)">
<!-- الاستراتيجية 3: التحميل المسبق للموارد عالية الأولوية -->
<link rel="preload" href="fonts/main.woff2" as="font" crossorigin>
<link rel="preload" href="critical.css" as="style">
<!-- الاستراتيجية 4: DNS prefetch لـ CSS الخارجي -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter">