نظام تصميم بالمتغيرات — CSS المتقدم
نظام تصميم بالمتغيرات
في دورة تصميم CSS تعلمت المتغيرات الأساسية. الآن نبني بها نظام تصميم: مجموعة قرارات ثابتة (ألوان، مسافات، خطوط، زوايا) تستخدمها كل المكوّنات، فيصبح الموقع متسقاً وتغييره سهلاً.
طبقتان من الرموز
:root {
/* 1) رموز أولية: القيم الخام — لا تستخدمها المكوّنات مباشرة */
--indigo-500: #6366f1;
--indigo-700: #4338ca;
--gray-50: #f9fafb;
--gray-900: #111827;
--red-600: #dc2626;
/* 2) رموز دلالية: الدور — هذه ما تستخدمه المكوّنات */
--color-brand: var(--indigo-500);
--color-brand-strong: var(--indigo-700);
--color-bg: var(--gray-50);
--color-text: var(--gray-900);
--color-danger: var(--red-600);
}تغيير هوية الموقع (البنفسجي إلى أخضر) = تعديل الطبقة الدلالية فقط.
مقاييس بدل أرقام عشوائية
:root {
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: clamp(1.125rem, 1rem + 0.5vw, 1.25rem);
--text-2xl: clamp(1.5rem, 1.2rem + 1.5vw, 2rem);
--radius-sm: 6px;
--radius-md: 12px;
--shadow-md: 0 4px 12px rgb(0 0 0 / 10%);
}عندما يسأل أحد "كم المسافة هنا؟" يكون الجواب واحداً من المقياس، لا 13px أو 17px.
color-mix: درجات من لون واحد
.btn:hover { background: color-mix(in oklch, var(--color-brand), black 15%); }
.badge { background: color-mix(in oklch, var(--color-brand) 15%, transparent); }بدل تعريف 10 درجات يدوياً، اشتقها من اللون الأساسي. oklch فضاء ألوان يعطي خلطاً يبدو طبيعياً للعين.
light-dark(): الوضع الليلي في سطر
:root {
color-scheme: light dark; /* يخبر المتصفح أننا ندعم الوضعين */
--color-bg: light-dark(#f9fafb, #0f172a);
--color-text: light-dark(#111827, #e5e7eb);
}light-dark(فاتح، داكن) تختار حسب تفضيل النظام (أو color-scheme على العنصر). و color-scheme يجعل أشرطة التمرير وحقول النماذج الافتراضية داكنة أيضاً. مدعومة في المتصفحات الحديثة منذ 2024؛ للقديمة استخدم أسلوب prefers-color-scheme.
متغيرات المكوّن: واجهة للتخصيص
.btn {
--btn-bg: var(--color-brand);
--btn-fg: white;
--btn-pad: var(--space-2) var(--space-4);
background: var(--btn-bg);
color: var(--btn-fg);
padding: var(--btn-pad);
border-radius: var(--radius-sm);
}
.btn.danger { --btn-bg: var(--color-danger); }
.btn.ghost { --btn-bg: transparent; --btn-fg: var(--color-brand); }
.btn.small { --btn-pad: var(--space-1) var(--space-3); }المتغيرات المحلية تعمل كـ"خيارات" للمكوّن: كل نسخة تغيّر الخيارات فقط، والقاعدة الأساسية مكتوبة مرة واحدة.
CSS Nesting (أصلي في المتصفح)
.card {
padding: var(--space-4);
border-radius: var(--radius-md);
& h3 { margin-block: 0 var(--space-2); }
&:hover { box-shadow: var(--shadow-md); }
@media (min-width: 768px) {
padding: var(--space-6);
}
}& يعني المحدد الأب. مدعوم في كل المتصفحات الحديثة منذ 2023 — لم تعد تحتاج Sass لهذا. لا تتعمق أكثر من مستويين أو ثلاثة: التداخل العميق يرفع الأولوية ويصعب القراءة.
@property: متغيرات قابلة للتحريك
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
.ring { background: conic-gradient(from var(--angle), var(--color-brand), transparent); animation: turn 3s linear infinite; }
@keyframes turn { to { --angle: 360deg; } }المتغير العادي لا يتحرك بسلاسة (المتصفح لا يعرف نوعه)؛ @property يعرّف نوعه فيصبح قابلاً للتحريك.
تمرين
أنشئ ملف tokens.css بطبقتي الرموز ومقاييس المسافات والخطوط، وحوّل أزرارك إلى مكوّن بمتغيرات (عادي، خطر، شفاف، صغير). استخدم color-mix لحالة hover و light-dark للوضع الليلي.
/* ===== tokens.css ===== */
:root {
color-scheme: light dark;
/* رموز أولية */
--indigo-500: #6366f1;
--red-600: #dc2626;
/* رموز دلالية */
--color-brand: var(--indigo-500);
--color-danger: var(--red-600);
--color-bg: light-dark(#f9fafb, #0f172a);
--color-surface: light-dark(#ffffff, #1e293b);
--color-text: light-dark(#111827, #e5e7eb);
/* مقاييس */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--radius-sm: 6px;
--radius-md: 12px;
--shadow-md: 0 4px 12px rgb(0 0 0 / 10%);
}
body {
background: var(--color-bg);
color: var(--color-text);
}
/* ===== مكوّن الزر: متغيرات كخيارات ===== */
.btn {
--btn-bg: var(--color-brand);
--btn-fg: white;
--btn-pad: var(--space-2) var(--space-4);
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: var(--btn-pad);
border: 1px solid transparent;
border-radius: var(--radius-sm);
background: var(--btn-bg);
color: var(--btn-fg);
font: inherit;
cursor: pointer;
transition: background-color 200ms ease-out;
&:hover {
background: color-mix(in oklch, var(--btn-bg), black 15%);
}
&:focus-visible {
outline: 3px solid color-mix(in oklch, var(--btn-bg) 60%, transparent);
outline-offset: 2px;
}
&.danger {
--btn-bg: var(--color-danger);
}
&.ghost {
--btn-bg: transparent;
--btn-fg: var(--color-brand);
border-color: currentColor;
}
&.small {
--btn-pad: var(--space-1) var(--space-3);
}
}
/* ===== مكوّن البطاقة ===== */
.card {
padding: var(--space-4);
border-radius: var(--radius-md);
background: var(--color-surface);
&:hover {
box-shadow: var(--shadow-md);
}
@media (min-width: 768px) {
padding: var(--space-6);
}
}اختبر فهمك