سازمان‌دهی متغیرها در پروژه‌های واقعی: Global و Component Variables

در درس‌های قبل، Custom Properties رو، هم روی :root و هم روی Selectorهای محلی‌تر، دیدیم. حالا وقتشه یک قدم عملی‌تر برداریم: چطور، در یک پروژه واقعی، بین متغیرهای سراسری (Global) و متغیرهای مخصوص یک کامپوننت (Component)، تمایز قائل بشیم؛ و چرا این تفکیک، برای نگهداری بلندمدت یک پروژه، اهمیت داره.

Global Variables: تعریف‌شده یک‌بار، استفاده در همه‌جا

:root {
  --color-primary: #1a73e8;
  --color-secondary: #34a853;
  --color-text: #202124;
  --color-background: #ffffff;
  --spacing-unit: 8px;
  --font-family-base: "Vazirmatn", sans-serif;
  --radius-base: 6px;
}

Global Variables (متغیرهای سراسری)، همون‌طور که در درس ۱۶-۱ دیدیم، روی :root تعریف می‌شن و در سراسر سند، در دسترسن. این متغیرها، معمولاً شامل مقادیر بنیادی و تکرارشونده‌ای هستن که هویت بصری کلی یک پروژه رو می‌سازن: رنگ‌های برند، فونت پایه، واحد فاصله‌گذاری، و شعاع گردی پیش‌فرض.

Component Variables: تعریف‌شده نزدیک محل استفاده

.card {
  --card-padding: 20px;
  --card-bg: var(--color-background);
  --card-border-radius: var(--radius-base);

  padding: var(--card-padding);
  background-color: var(--card-bg);
  border-radius: var(--card-border-radius);
}

Component Variables (متغیرهای مخصوص کامپوننت)، روی خود Selector همون کامپوننت (نه :root) تعریف می‌شن و معمولاً، مقادیری هستن که فقط به همون یک کامپوننت خاص مربوطن؛ مثل --card-padding که فقط برای کارت‌ها معنا داره، نه برای دکمه‌ها یا فرم‌ها.

الگوی رایج: Component Variables، خودشان به Global Variables ارجاع می‌دهند

در مثال بالا، دقت کن که --card-bg و --card-border-radius، خودشون، مستقیماً به متغیرهای سراسری (--color-background و --radius-base) ارجاع دادن، نه یک مقدار خام جدید. این الگو، یک لایه میانی می‌سازه: کامپوننت، به‌جای وابستگی مستقیم به یک متغیر سراسری، به یک متغیر محلی خودش وابسته‌ست که، به‌طور پیش‌فرض، از همون مقدار سراسری تغذیه می‌کنه.

چرا این لایه میانی مفید است؟

.card.card--featured {
  --card-bg: var(--color-secondary);
}

مزیت اصلی این الگو، اینه که حالا می‌شه، فقط برای یک نسخه خاص از کامپوننت (مثلاً یک کارت «ویژه»)، همون متغیر محلی رو Override کرد؛ بدون این‌که مقدار سراسری --color-background (که احتمالاً جاهای دیگه هم استفاده می‌شه) رو، اصلاً دست بزنیم. این دقیقاً همون تکنیک Scope و Override‌ای‌ست که در درس ۱۶-۳ دیدیم، ولی این‌بار، در یک ساختار سازمان‌یافته و قابل‌نگهداری.

یک مثال کامل: دکمه با متغیرهای دو سطحی

:root {
  --color-primary: #1a73e8;
  --spacing-unit: 8px;
  --radius-base: 6px;
}

.button {
  --button-bg: var(--color-primary);
  --button-padding-y: var(--spacing-unit);
  --button-padding-x: calc(var(--spacing-unit) * 3);
  --button-radius: var(--radius-base);

  background-color: var(--button-bg);
  padding: var(--button-padding-y) var(--button-padding-x);
  border-radius: var(--button-radius);
}

.button--danger {
  --button-bg: crimson;
}
<button class="button">دکمه معمولی</button>
<button class="button button--danger">دکمه خطر</button>

در این مثال، .button، مجموعه‌ای از متغیرهای محلی خودش رو تعریف می‌کنه، که بعضی‌شون (مثل --button-bg)، از متغیرهای سراسری تغذیه می‌کنن. کلاس .button--danger، فقط با Override کردن یک متغیر محلی (--button-bg)، رنگ دکمه رو تغییر می‌ده؛ بدون این‌که مجبور باشیم بقیه Propertyها (مثل Padding یا Radius) رو، دوباره از نو تعریف کنیم.

جدول جمع‌بندی: چه زمانی Global، چه زمانی Component؟

معیار Global Variable Component Variable
محل تعریف :root روی خود Selector کامپوننت
دامنه استفاده در سراسر پروژه محدود به همان کامپوننت و نسخه‌های آن
مثال --color-primary، --spacing-unit --card-padding، --button-bg
هدف اصلی یکپارچگی هویت بصری کل پروژه انعطاف‌پذیری و قابلیت شخصی‌سازی یک کامپوننت خاص

یک قرارداد نام‌گذاری رایج (نه اجباری)

:root {
  --color-primary: #1a73e8; /* بدون پیشوند کامپوننت خاص */
}

.card {
  --card-padding: 20px; /* پیشوند card- برای مشخص کردن تعلق به این کامپوننت */
}

هرچند CSS، هیچ قانون اجباری‌ای برای نام‌گذاری متغیرها نداره، ولی یک قرارداد بسیار رایج در پروژه‌های واقعی، اینه که نام متغیرهای Component، با نام همون کامپوننت (مثل card- یا button-) شروع بشه؛ این کار، هم خوانایی کد رو بهتر می‌کنه، و هم از تداخل تصادفی نام‌ها بین کامپوننت‌های مختلف جلوگیری می‌کنه.

نکات مهم

  • Global Variables، روی :root تعریف می‌شوند و مقادیر بنیادی و تکرارشونده هویت بصری کل پروژه را نگه می‌دارند.
  • Component Variables، روی خود Selector یک کامپوننت تعریف می‌شوند و معمولاً به Global Variables ارجاع می‌دهند، نه مقدار خام جدید.
  • این ساختار دو سطحی، امکان Override کردن یک نسخه خاص از یک کامپوننت (مثل یک دکمه «خطر») را، بدون تأثیر بر بقیه پروژه، فراهم می‌کند.

اشتباهات رایج

  • تعریف تمام متغیرها، حتی موارد کاملاً مخصوص یک کامپوننت، روی :root، که با گذشت زمان، سند :root را شلوغ و غیرقابل‌مدیریت می‌کند.
  • استفاده مستقیم از متغیرهای سراسری در چند جای یک کامپوننت، به‌جای ساختن یک لایه میانی از متغیرهای محلی؛ که Override کردن یک حالت خاص را دشوارتر می‌کند.
  • نام‌گذاری متغیرهای محلی بدون پیشوند کامپوننت، که احتمال تداخل نام بین کامپوننت‌های مختلف را افزایش می‌دهد.

جمع‌بندی

در پروژه‌های واقعی، Custom Properties معمولاً در دو سطح سازمان‌دهی می‌شوند: Global Variables روی :root، برای مقادیر بنیادی و مشترک کل پروژه، و Component Variables روی خود کامپوننت، برای مقادیر مخصوص همان بخش. الگوی رایج، اتصال متغیرهای محلی به متغیرهای سراسری (نه استفاده مستقیم از خود متغیر سراسری در چند جا)، این امکان را می‌دهد که نسخه‌های خاص یک کامپوننت، به‌سادگی و بدون تأثیر جانبی، Override شوند.