Design Tokens؛ وقتی مقادیر طراحی یه منبع واحد پیدا می‌کنن

تو دو درس قبل با دو فلسفه‌ی متفاوت برای سازماندهی کلاس‌ها آشنا شدیم: BEM و Utility. اما یه سؤال دیگه هم هست که مستقل از این انتخابه: از کجا بفهمیم که رنگ آبی برند دقیقاً چه کدیه، یا فاصله‌ی استاندارد بین بخش‌ها چند پیکسله؟ اگه این مقادیر تو ده‌ها جای پروژه پخش و تکرار شده باشن، هر تغییر کوچیک طراحی تبدیل به یه کابوس می‌شه. Design Tokens دقیقاً همین مشکل رو حل می‌کنن، و تو CSS، custom property ها (که تو فصل ۱۶ باهاشون آشنا شدیم) ابزار اصلی پیاده‌سازیشونن.

Design Token دقیقاً چیه؟

یه design token، یه مقدار طراحی (رنگ، فاصله، سایز فونت، شعاع گردی و غیره) هست که به‌جای این‌که مستقیم و تکراری تو کد نوشته بشه، یه اسم معنایی می‌گیره و از یه‌جای مرکزی مدیریت می‌شه. تفاوتش با یه custom property معمولی اینه که token ها بخشی از یه سیستم طراحی مستندشده و هدفمندن، نه فقط یه متغیر تصادفی:

/* بدون token: همین مقدار جای‌جای پروژه تکرار می‌شه */
.btn { background: #3b82f6; }
.link { color: #3b82f6; }
.badge { border-color: #3b82f6; }

/* با token: یه منبع واحد */
:root {
  --color-brand: #3b82f6;
}
.btn { background: var(--color-brand); }
.link { color: var(--color-brand); }
.badge { border-color: var(--color-brand); }

حالا اگه رنگ برند عوض بشه، فقط یه خط باید تغییر کنه، نه ده‌ها جای پراکنده.

لایه‌بندی Token ها: از خام تا معنایی

یه الگوی رایج و قدرتمند تو سیستم‌های طراحی بزرگ، تعریف token ها تو دو (یا بیشتر) لایه‌ست: لایه‌ی «خام» (primitive) که فقط مقادیر پایه رو نگه می‌داره، و لایه‌ی «معنایی» (semantic) که به این مقادیر یه نقش می‌ده:

:root {
  /* لایه‌ی خام: فقط مقادیر، بدون معنا */
  --blue-500: #3b82f6;
  --blue-700: #1d4ed8;
  --red-500: #ef4444;

  /* لایه‌ی معنایی: نقش هر مقدار تو UI */
  --color-primary: var(--blue-500);
  --color-primary-hover: var(--blue-700);
  --color-danger: var(--red-500);
}

.btn-primary {
  background: var(--color-primary);
}
.btn-primary:hover {
  background: var(--color-primary-hover);
}

مزیت این جداسازی اینه: اگه بخواید کل تم رنگی برند رو عوض کنید (مثلاً از آبی به بنفش)، فقط باید لایه‌ی معنایی رو به یه ست رنگ دیگه وصل کنید؛ لایه‌ی خام دست‌نخورده می‌مونه و می‌تونه حتی تو پروژه‌های دیگه هم دوباره استفاده بشه.

Token های فاصله‌گذاری: یه مقیاس ثابت

یکی از رایج‌ترین و مفیدترین انواع token، مقیاس فاصله‌گذاریه؛ به‌جای این‌که هر جای پروژه یه عدد دلخواه (13px، 18px، 22px) بذارید، یه مقیاس محدود و هماهنگ تعریف می‌کنید:

:root {
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 16px;
  --space-4: 24px;
  --space-5: 32px;
  --space-6: 48px;
}

.card {
  padding: var(--space-3);
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

این محدودیت عمدیه؛ وقتی فقط ۶ گزینه دارید (نه بی‌نهایت عدد دلخواه)، تصمیم‌گیری برای فاصله‌ها سریع‌تر می‌شه و ظاهر کل سایت هماهنگ‌تر به نظر می‌رسه، چون همه از همون ریتم بصری پیروی می‌کنن.

Token های تایپوگرافی

:root {
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.25rem;
  --font-size-xl: 1.5rem;

  --font-weight-normal: 400;
  --font-weight-bold: 700;

  --line-height-tight: 1.2;
  --line-height-normal: 1.5;
}

h2 {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
}

ارتباط با prefers-color-scheme (فصل ۲۳)

تو فصل قبلی درباره‌ی Accessibility، دیدیم چطور با custom property ها و media query، یه سیستم رنگ برای حالت روشن/تاریک می‌سازیم. اون دقیقاً همین الگوی design token بود؛ لایه‌ی معنایی token ها (مثل --color-bg) بسته به شرایط (حالت روشن یا تاریک، یا انتخاب دستی کاربر) به مقادیر متفاوتی وصل می‌شه، بدون این‌که خود کلاس‌هایی که ازشون استفاده می‌کنن تغییری کنن:

:root {
  --color-bg: white;
  --color-text: #1a1a1a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #121212;
    --color-text: #f0f0f0;
  }
}

body {
  background: var(--color-bg);
  color: var(--color-text);
}

Token ها فراتر از CSS: ارتباط با ابزارهای طراحی

یه نکته‌ی مهم اینه که design token ها معمولاً محدود به CSS نیستن؛ خیلی از تیم‌ها همین مقادیر رو تو ابزارهای طراحی (مثل Figma) هم به همون اسم تعریف می‌کنن، تا طراح و توسعه‌دهنده دقیقاً از یه زبان مشترک استفاده کنن. بعضی پروژه‌ها حتی از فرمت‌های میانی (مثل JSON) استفاده می‌کنن که هم به CSS custom property تبدیل بشه، هم به فرمت‌های دیگه (مثل متغیرهای iOS یا Android) برای پروژه‌های موبایل؛ این‌جوری یه منبع واحد، چند پلتفرم مختلف رو تغذیه می‌کنه. این بخش معمولاً از حوزه‌ی خود CSS بیرونه و به تولینگ پروژه بستگی داره، ولی دونستن مفهومش کمک می‌کنه بفهمید چرا بعضی پروژه‌های بزرگ این‌قدر روی نام‌گذاری دقیق token ها حساسن.

نکته مهم: وسوسه نشید که برای هر مقدار احتمالی یه token بسازید. یه سیستم token خوب، محدود و هدفمنده؛ اگه برای هر پیکسل دلخواه یه متغیر جدید بسازید، عملاً همون مشکل قبلی (بی‌نظمی و تکرار) رو با یه اسم متغیر پیچیده‌تر بازسازی کردید.

اشتباه رایج: استفاده‌ی مستقیم از token های خام به‌جای معنایی

یه اشتباه رایج اینه که مستقیم از token های لایه‌ی خام تو کامپوننت‌ها استفاده کنید، به‌جای لایه‌ی معنایی:

/* اشتباه: وابستگی مستقیم به رنگ خام */
.btn-danger {
  background: var(--red-500);
}

/* درست: وابستگی به نقش معنایی */
.btn-danger {
  background: var(--color-danger);
}

مشکل حالت اول اینه که اگه بعداً بخواید رنگ خطا رو از قرمز به یه رنگ دیگه عوض کنید، باید همه‌جایی که مستقیم به --red-500 وصل شده رو پیدا و عوض کنید؛ در حالی که اگه از اول به --color-danger وصل بود، فقط تعریف اون یه token تو لایه‌ی معنایی عوض می‌شد.

جمع‌بندی

Design token ها، مقادیر طراحی (رنگ، فاصله، فونت) رو از یه منبع مرکزی مدیریت می‌کنن تا تغییرات آینده ساده و بدون جست‌وجوی سراسری پروژه انجام بشن. لایه‌بندی token ها به «خام» و «معنایی» اجازه می‌ده تم کلی سایت (مثل حالت روشن/تاریک یا تغییر برند) رو فقط با تغییر لایه‌ی معنایی عوض کنید. همیشه تو کامپوننت‌ها به token های معنایی وصل بشید، نه مستقیم به مقادیر خام.