هكلمك في حاجات advanced محدش هيقولهالك عن الـ CSS
📚 المحتوى
- CSS Variables
- Custom Selectors والـ Logical Operations
- State Machines في CSS
- Advanced Animations & Performance
- Modern Layout Techniques
- Browser Rendering Optimization
🎯 المتغيرات في CSS
Type-Checking في CSS Variables
دي طريقة نعمل بيها validation للمتغيرات في CSS يعني نتأكد إن المتغير هياخد نوع معين من القيم وبس
@property --theme-color {
syntax: '<color>';
inherits: false;
initial-value: #1a1a1a;
}
@property --scale {
syntax: '<number>';
inherits: true;
initial-value: 1;
}
في المثال الأول:
- عملنا متغير اسمه theme-color
- قلنا انه لازم ياخد لون بس (color)
- لو محدش حط قيمة هياخد اللون #1a1a1a
- وقلنا انه مش هيورث القيمة من العناصر اللي فوقه
في المثال التاني:
- عملنا متغير اسمه scale
- قلنا انه لازم ياخد رقم بس (number)
- لو محدش حط قيمة هياخد الرقم 1
- وقلنا انه هيورث القيمة من العناصر اللي فوقه
الكلام ده مفيد لما نكون عايزين نتأكد إن حد مش هيحط قيم غلط في المتغيرات
ملحوظة: الـ syntax بتحدد نوع القيمة اللي المتغير هياخدها
- `<number>` للأرقام زي 1, 2, 3.14
- `<percentage>` للنسب المئوية زي 50%, 100%
- `<length>` للمقاسات زي 10px, 2rem
- `<color>` للألوان زي #fff, rgb(0,0,0)
- `<image>` للصور
- `<url>` للروابط
- `*` لأي نوع من القيم
Scoped Variables (نطاق المتغيرات)
هنا بنعمل متغيرات خاصة بالكومبوننت دا بس يعني مش هتأثر على حاجة تانية في الموقع
.component {
--private-spacing: 1rem; /* دا متغير عادي للمسافات */
--_internal-radius: 8px; /* دا متغير داخلي، الشرطة في الأول معناها إنه متغير خاص جداً */
}
دي طريقة ذكية نعمل بيها نظام ألوان متغير بنقسم اللون لـ 3 أجزاء (درجة اللون، التشبع، الإضاءة) وكدا نقدر نتحكم في كل جزء لوحده الفكرة ببساطة إننا بنقسم اللون لـ 3 حاجات:
- درجة اللون (Hue): دي بتحدد نوع اللون نفسه (أحمر، أزرق، أخضر، إلخ) وبتاخد رقم من 0 لـ 360
- التشبع (Saturation): دي بتحدد قوة اللون، من الرمادي (0%) للون النقي (100%)
- الإضاءة (Lightness): دي بتحدد درجة سطوع اللون، من الأسود (0%) للأبيض (100%)
لما نفصل اللون كدا، بيبقى سهل نعمل درجات مختلفة من نفس اللون زي مثلاً نسخة فاتحة أو غامقة، أو نغير قوة اللون
.theme-container {
--primary-h: 220; /* درجة اللون (من 0 لـ 360) */
--primary-s: 90%; /* نسبة التشبع */
--primary-l: 50%; /* نسبة الإضاءة */
/* بنجمع الأجزاء التلاتة مع بعض عشان نعمل اللون الأساسي */
--primary: hsl(
var(--primary-h)
var(--primary-s)
var(--primary-l)
);
/*
وهنا بنعمل نسخة أفتح من نفس اللون
بنزود الإضاءة بـ 20%
*/
--primary-light: hsl(
var(--primary-h)
var(--primary-s)
calc(var(--primary-l) + 20%)
);
}
Tailwind بتستخدم نظام الألوان بطريقة مختلفة عن HSL المباشر:
/* نظام الألوان في Tailwind */
:root {
/* كل لون بيتقسم لـ 10 درجات من 50 لـ 900 */
--blue-50: hsl(214, 100%, 97%); /* أفتح درجة */
--blue-100: hsl(214, 95%, 93%);
--blue-200: hsl(213, 97%, 87%);
--blue-300: hsl(212, 96%, 78%);
--blue-400: hsl(213, 94%, 68%);
--blue-500: hsl(217, 91%, 60%); /* اللون الأساسي */
--blue-600: hsl(221, 83%, 53%);
--blue-700: hsl(224, 76%, 48%);
--blue-800: hsl(226, 71%, 40%);
--blue-900: hsl(224, 64%, 33%); /* أغمق درجة */
/* وكدا مع باقي الألوان */
--red-500: hsl(0, 84%, 60%);
--green-500: hsl(142, 76%, 36%);
/* إلخ... */
}
/* وبعدين بتستخدمهم في الـ utilities */
.bg-blue-500 {
background-color: var(--blue-500);
}
.text-blue-700 {
color: var(--blue-700);
}
/* ودا مثال للـ opacity modifiers */
.bg-blue-500\/50 {
background-color: hsl(217 91% 60% / 0.5);
}
هتيجي تسأل نفسك سؤال مهم جداً: إزاي Tailwind بتعمل auto Generate للـ utilities؟
/*
Tailwind بتعمل auto generate للألوان بالطريقة دي:
1. بتبدأ بتعريف الألوان الأساسية في ملف الكونفيج
*/
const colors = {
blue: {
50: 'hsl(214, 100%, 97%)',
100: 'hsl(214, 95%, 93%)',
200: 'hsl(213, 97%, 87%)',
300: 'hsl(212, 96%, 78%)',
400: 'hsl(213, 94%, 68%)',
500: 'hsl(217, 91%, 60%)',
600: 'hsl(221, 83%, 53%)',
700: 'hsl(224, 76%, 48%)',
800: 'hsl(226, 71%, 40%)',
900: 'hsl(224, 64%, 33%)',
}
}
/*
2. بعدين بتعمل loop على كل لون وتنشئ الـ CSS classes
*/
Object.entries(colors).forEach(([color, shades]) => {
Object.entries(shades).forEach(([shade, value]) => {
// Background classes
`.bg-${color}-${shade}` {
background-color: ${value};
}
// Text classes
`.text-${color}-${shade}` {
color: ${value};
}
// Border classes
`.border-${color}-${shade}` {
border-color: ${value};
}
// Opacity variants
[1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95].forEach(opacity => {
`.bg-${color}-${shade}/${opacity}` {
background-color: ${value.replace(')', ` / ${opacity}%)`)};
}
});
});
});
🧮 state machine في CSS
دي حاجة في CSS بتخليك تتحكم في حالات العناصر بتاعتك من غير ما تحتاج جافاسكريبت
يعني مثلا لو عندك زرار بيتغير شكله لما تدوس عليه او مثلا قائمة بتظهر وتختفي او اي حاجة تانية محتاجة تتغير حالتها
كل دا ممكن تعمله بالـ CSS بس من غير جافاسكريبت وهنشوف ازاي في المثال اللي جاي
Toggle System بدون JavaScript
دي طريقة بسيطة لعمل زرار بيظهر ويخفي محتوى من غير جافاسكريبت بنعمل متغير اسمه is-active قيمته 0 في الأول ولما نضغط على الـ checkbox بيتغير لـ 1 وبعدين بنستخدم المتغير دا في تغيير شكل المحتوى
.toggle-container {
--is-active: 0;
&:has(:checked) {
--is-active: 1;
}
}
.toggle-content {
opacity: var(--is-active);
transform: scale(calc(0.8 + (var(--is-active) * 0.2)));
transition: all 0.3s ease;
}
Advanced Selectors & Combinators
دي سيليكتورات متقدمة في CSS بتخليك تتحكم في العناصر بطريقة ذكية
لما تعمل hover على الـ header بيعمل blur للـ content
.card:has(.header:hover) .content {
filter: blur(2px);
}
لما تعمل hover او focus على العنصر وفي نفس الوقت مش disabled ومش مخفي بيتحرك لفوق شوية
.element:is(:hover, :focus-within):not([disabled], [aria-hidden="true"]) {
transform: translateY(-2px);
}
لو عندك grid وفيه اكتر من 4 عناصر بيغير شكل الـ grid تلقائي عشان يظبط العناصر
.grid:has(> :nth-child(n+5)) {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
🎨 Dynamic Viewport Units
.hero {
/* dvh بتظبط ارتفاع العنصر تلقائي حسب حجم الشاشة
وبتاخد في الاعتبار شريط العنوان في الموبايل
لما يظهر ويختفي */
min-height: 100dvh;
/* بنحط padding فوق وتحت بقيمة ديناميكية
10% من ارتفاع الشاشة + 1rem ثابت */
padding-block: calc(10dvh + 1rem);
}
.text {
/* cqi و cqw دول وحدات جديدة للـ Container Queries
cqi = Container Query Inline Size
cqw = Container Query Width
max() بتختار القيمة الأكبر من:
- 2cqi: حجم الخط = 2% من عرض الـ container
- 16px: الحد الأدنى للخط عشان يفضل مقروء
min() بتختار القيمة الأصغر من:
- 4cqw: padding = 4% من عرض الـ container
- 2rem: الحد الأقصى للـ padding */
font-size: max(2cqi, 16px);
padding-inline: min(4cqw, 2rem);
/* كمان ممكن نستخدم:
svh = Small Viewport Height
lvh = Large Viewport Height
للتحكم في الارتفاع حسب حالة شريط العنوان */
}
/* في Tailwind نقدر نستخدم Dynamic Units بالشكل دا:
min-h-[100dvh] // dynamic viewport height
p-[10dvh] // dynamic viewport padding
text-[2cqi] // container query inline size
px-[4cqw] // container query width padding
h-[100svh] // small viewport height
h-[100lvh] // large viewport height
*/
⚡ Performance Optimization
تحسين الأداء باستخدام Content-Visibility و Will-Change
دي خصائص جديدة في CSS بتساعد في تحسين أداء الصفحة:
Content-Visibility: بتخلي المتصفح يتجاهل رسم العناصر اللي مش ظاهرة في الشاشة، وبكدا بتوفر موارد المعالجة وبتسرع تحميل الصفحة
Will-Change: بتدي تلميح للمتصفح إن العنصر هيتغير (مثلاً هيتحرك)، فيقدر يجهز نفسه ويستخدم معالج الرسومات GPU للتحريك بشكل أسرع وأنعم
.card {
/* دي بتخلي المتصفح ميرسمش المحتوى اللي مش ظاهر في الشاشة
وبكدا بتحسن الأداء جامد */
content-visibility: auto;
/* دي بتديله تلميح عن حجم المحتوى قبل ما يتحمل
عشان ميحصلش قفزة في الصفحة */
contain-intrinsic-size: 200px;
/* دي بتقول للمتصفح إن العنصر هيتحرك
فيجهز نفسه ويحسن الأداء */
will-change: transform;
/* دي مدة التحريك - نص ثانية */
transition: transform 0.2s;
/* هنا بنشوف لو المستخدم مش عايز حركات في النظام عنده
لو عايز حركات عادي هننفذ اللي تحت */
@media (prefers-reduced-motion: no-preference) {
/* لما نحط الماوس على الكارت
هيتحرك لفوق 4 بكسل */
&:hover {
transform: translateY(-4px);
}
}
}
GPU-Accelerated Animations
الـ GPU هو كرت الشاشة اللي بيساعد في تشغيل الجرافيكس والحركات بشكل أسرع وأنعم. لما نستخدم خصائص معينة في CSS زي transform و opacity، المتصفح بيشغل الحركات دي على كرت الشاشة بدل المعالج العادي، وده بيخلي الحركات تبقى أسرع وأنعم وبتاكل مساحة أقل من المعالج.
هنا بنعمل حركة اسمها smooth-parallax بتخلي العنصر يتحرك مع السكرول بشكل سلس
@keyframes smooth-parallax {
to {
/* بنحرك العنصر في اتجاه Y بمقدار متغير --scroll-offset
واستخدمنا translate3d عشان نشغل الـ GPU */
transform: translate3d(0, var(--scroll-offset), 0);
}
}
.parallax-element {
/* بنطبق الحركة على العنصر وبنخليها تمشي مع السكرول */
animation: smooth-parallax linear both;
animation-timeline: scroll();
/* الحركة هتبدأ لما 20% من العنصر يظهر
وتكمل لحد ما 80% منه يتغطى */
animation-range: entry 20% cover 80%;
/* دول 3 خصائص بيحسنوا أداء الحركة:
- backface-visibility: hidden بتخفي الوش الخلفي للعنصر
- perspective: بتدي عمق 3D للعنصر
- transform-style: preserve-3d بتخلي العنصر يتعامل في الـ 3D */
backface-visibility: hidden;
perspective: 1000px;
transform-style: preserve-3d;
/* بنضيف will-change عشان نحسن الأداء */
will-change: transform;
/* بنضيف contain عشان نمنع تأثير الحركة على العناصر المحيطة */
contain: paint;
/* بنضيف z-index عشان نتحكم في ترتيب العناصر */
z-index: 1;
/* بنضيف transition للحركات الأخرى */
transition: opacity 0.3s ease;
}
/* بنضيف media query للأجهزة اللي مش عايزة حركات */
@media (prefers-reduced-motion: reduce) {
.parallax-element {
animation: none;
transform: none;
}
}
التحكم المتقدم في الألوان
.gradient-text {
/* هنا بنعرف متغيرين للألوان:
- الأول للون البداية: لون فاتح مايل للأزرق
- التاني للون النهاية: لون غامق مايل للتركواز
OKLCH بيديك تحكم أدق في الألوان */
--gradient-start: oklch(80% 0.15 230);
--gradient-end: oklch(50% 0.25 180);
/* بنعمل تدرج لوني (جراديانت) من الشمال لليمين
باستخدام المتغيرين اللي عرفناهم فوق */
background: linear-gradient(
to right,
var(--gradient-start),
var(--gradient-end)
);
/* دي بقى الخدعة - بنخلي التدرج يظهر على النص بس
لازم نحط الاتنين عشان يشتغل في كل المتصفحات */
background-clip: text;
-webkit-background-clip: text;
/* بنخلي لون النص شفاف عشان يظهر التدرج من تحته */
color: transparent;
/* بنضيف ضل خفيف للنص عشان يبقى أوضح للقراية
بناخد قيم RGB من لون البداية ونخليه شفاف 10% */
text-shadow: 0 1px 2px rgb(from var(--gradient-start) r g b / 10%);
}
🎭 Advanced Pseudo-Classes
Focus Management
/* نظام الفوكس المتقدم - بيخلي شكل العناصر احلى لما تضغط عليها */
:focus-visible {
outline: none; /* بنشيل البوردر الافتراضي */
box-shadow: 0 0 0 4px rgb(0 100 255 / 0.3); /* بنحط ضل ازرق شفاف شوية */
border-radius: 4px; /* بنعمل الحواف مدورة */
transition: box-shadow 0.2s ease; /* بنخلي التغيير ناعم */
}
/* دي بتشتغل لما تضغط بالماوس - مش محتاجين نظهر الفوكس */
:focus:not(:focus-visible) {
outline: none;
box-shadow: none;
}
/* دي بقى للناس اللي بيستخدموا الكيبورد في التصفح */
:focus {
/* لما يكون الفوكس بالماوس */
&:not(:focus-visible) {
outline: none;
}
/* لما يكون الفوكس بالكيبورد */
&-visible {
outline-offset: 4px; /* بنبعد الفوكس عن العنصر شوية */
outline: 2px solid currentColor; /* بنحط بوردر بلون العنصر نفسه */
}
}
/* بنضيف دعم للناس اللي مش حابين الحركات */
@media (prefers-reduced-motion: reduce) {
:focus-visible {
transition: none;
}
}
🔄 Advanced Layout Patterns
تنسيق Subgrid
/* الشبكة الرئيسية - بتقسم الصفحة ل 12 عمود متساوي */
.grid-container {
display: grid;
grid-template-columns: repeat(12, 1fr);
/* المسافة بين العناصر بتتغير حسب حجم الشاشة */
gap: clamp(1rem, 3vw, 2rem);
}
/* الشبكة الفرعية - بتورث نظام الصفوف من الشبكة الأم */
.nested-grid {
/* بتاخد مساحة 4 أعمدة */
grid-column: span 4;
display: grid;
/* بتورث نفس نظام الصفوف من الأب */
grid-template-rows: subgrid;
/* ممكن نضيف خصائص كمان */
align-items: start;
justify-items: stretch;
}
تنسيق Masonry (زي بينترست)
.masonry {
display: grid;
/* بتعمل أعمدة تتكيف مع حجم الشاشة، كل عمود مينفعش يقل عن 300 بيكسل */
grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
/* نظام الـ masonry الجديد - زي بينترست */
grid-template-rows: masonry;
/* بتمد العناصر للحد الأقصى */
align-tracks: stretch;
/* المسافات بين العناصر */
gap: clamp(1rem, 2.5vw, 2rem);
/* بنضيف دعم للمتصفحات القديمة */
@supports not (grid-template-rows: masonry) {
display: flex;
flex-wrap: wrap;
}
/* تحسين مظهر العناصر جوا الشبكة */
> * {
break-inside: avoid;
margin-bottom: 1rem;
border-radius: 8px;
overflow: hidden;
}
}
🎯 نصائح عشان إنت مميز عشان وصلت هنا
- استخدم CSS Containment عشان تحسن الأداء:
بيخلي المتصفح يعامل العنصر كوحدة مستقلة - يعني مش هيأثر على باقي الصفحة contain: content
= بيحدد إن المحتوى جوا العنصر مش هيطلع برا حدوده contain-intrinsic-size
= بيديله حجم افتراضي قبل ما المحتوى يتحمل
.complex-component {
contain: content;
contain-intrinsic-size: 1000px;
/* ممكن نضيف كمان */
content-visibility: auto;
/* دي بتخلي المتصفح ميرسمش العناصر اللي برا الشاشة */
}
- استخدم Logical Properties عشان تدعم العربي والإنجليزي (RTL/LTR):
بدل ما نستخدم left/right نستخدم inline-start/inline-end
كده الكود هيشتغل صح مع العربي والإنجليزي تلقائي
.element {
margin-inline-start: 1rem; /* هيبقى يمين في العربي وشمال في الإنجليزي */
padding-block: 1rem; /* padding من فوق وتحت */
border-inline-end: 2px solid;
/* ممكن نضيف كمان */
text-align: start; /* بيظبط اتجاه النص حسب اللغة */
float: inline-start; /* بيظبط اتجاه العائم حسب اللغة */
}
- استخدم CSS Feature Queries بذكاء عشان تتأكد إن المتصفح بيدعم الخصائص الجديدة:
بنتأكد الأول إن المتصفح بيدعم grid و masonry لو مش بيدعم، هننفذ حل بديل
@supports (display: grid) and (not (overflow-x: clip)) {
.modern-layout {
display: grid;
grid-template: masonry / repeat(auto-fill, minmax(200px, 1fr));
}
}
/* حل بديل للمتصفحات القديمة */
@supports not (display: grid) {
.modern-layout {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
}
⚠️ ملاحظات مهمة جداً:
- دعم المتصفحات:
- لازم تتأكد الأول من caniuse.com قبل ما تستخدم أي خاصية CSS جديدة
- لازم تعمل بديل (fallback) للخصائص الجديدة عشان المتصفحات القديمة:
.element {
/* الحل القديم للمتصفحات القديمة */
width: 90%;
/* الحل الجديد للمتصفحات الحديثة */
width: clamp(300px, 90%, 1200px);
/* مثال تاني */
/* قديم */
margin: 20px;
/* جديد */
margin: min(20px, 3vw);
}
نصايح للأداء:
- متستخدمش الخصائص اللي بتاخد مجهود كبير من المتصفح زي
box-shadow
في الحركات - استخدم
transform
وopacity
في الحركات لأنهم أسرع وأخف - استخدم
will-change
بس لما تحتاجه بجد، لأنه بياخد من ذاكرة المتصفح
.button { /* كويس */ transition: transform 0.3s, opacity 0.3s; /* مش كويس */ transition: box-shadow 0.3s, width 0.3s; }
- متستخدمش الخصائص اللي بتاخد مجهود كبير من المتصفح زي
اكتشاف المشاكل:
- استخدم متغيرات CSS عشان تلاقي مشاكل التنسيق بسهولة:
:root {
--show-debug: 1px solid red;
--show-layout: 2px dashed blue;
}
/* هتظهرلك الحدود حوالين كل العناصر */
.debug * {
border: var(--show-debug);
}
/* هتظهر حدود للعناصر المهمة بس */
.container {
border: var(--show-layout);
outline: var(--show-debug);
}