وقتی دو Selector رقابت می‌کنند: مفهوم Specificity

تو درس قبل دیدیم که بعد از Origin و Importance، دومین عاملی که Cascade بررسی می‌کنه، Specificity‌ه. این مفهوم احتمالاً یکی از پرکاربردترین و در عین حال گاهی گیج‌کننده‌ترین بخش‌های CSS برای خیلی از توسعه‌دهنده‌هاست، پس بیایم قدم‌به‌قدم و دقیق باهاش آشنا بشیم.

Specificity چیست؟

Specificity (اختصاصیت) عددیه که مشخص می‌کنه یک Selector چقدر «دقیق و اختصاصی» نوشته شده. وقتی چند Rule با Origin و Importance یکسان روی یک عنصر اثر بذارن، مرورگر Specificity هر Selector رو محاسبه می‌کنه و Ruleای که Specificity بالاتری داره، برنده می‌شه.

چهار سطح محاسبه Specificity

Specificity معمولاً به‌صورت یک عدد چهاربخشی در نظر گرفته می‌شه که هر بخش، وزن متفاوتی داره:

سطح شامل چه Selectorهایی وزن
سطح ۱ Inline Style (روی خود تگ) بالاترین وزن
سطح ۲ ID Selector (مثل #header) وزن بالا
سطح ۳ Class، Attribute، Pseudo-class (مثل .box، [type="text"]، :hover) وزن متوسط
سطح ۴ Type Selector و Pseudo-element (مثل p، ::before) وزن پایین

Universal Selector (*) هیچ وزنی در Specificity نداره؛ یعنی عملاً مقدارش صفره.

روش نمایش Specificity

معمولاً Specificity رو به‌صورت یک مجموعه چهار عدد نشون می‌دن، به این شکل: (Inline, ID, Class, Type). بیایم چند مثال رو با هم محاسبه کنیم.

مثال ۱: یک Type Selector ساده

p {
  color: blue;
}

Specificity: (0, 0, 0, 1) → فقط یک Type Selector داریم.

مثال ۲: یک Class Selector

.title {
  color: green;
}

Specificity: (0, 0, 1, 0) → یک Class Selector داریم.

مثال ۳: یک ID Selector

#main-title {
  color: red;
}

Specificity: (0, 1, 0, 0) → یک ID Selector داریم.

مثال ۴: ترکیب چند Selector

div.container p.highlight {
  color: purple;
}

بیایم این Selector رو تیکه‌تیکه بشماریم:

  • div → یک Type Selector
  • .container → یک Class Selector
  • p → یک Type Selector دیگر
  • .highlight → یک Class Selector دیگر

Specificity: (0, 0, 2, 2) → دو Class و دو Type.

مقایسه Specificity بین چند Rule

فرض کن این دو Rule هم‌زمان روی یک عنصر اثر بذارن:

p {
  color: blue;
}

.highlight {
  color: green;
}
<p class="highlight">متن نمونه</p>

Specificity اولی (0,0,0,1) و دومی (0,0,1,0) است. چون سطح Class (سطح سوم) از سطح Type (سطح چهارم) مهم‌تره، مقدار سبز برنده می‌شه؛ صرف‌نظر از اینکه کدوم Rule اول یا آخر نوشته شده.

یک مثال پیچیده‌تر

#box p {
  color: orange;
}

.container .text {
  color: teal;
}

Specificity اولی: (0, 1, 0, 1) — یک ID و یک Type.
Specificity دومی: (0, 0, 2, 0) — دو Class.

برای مقایسه این دو، باید از چپ به راست مقایسه کنیم: اول عدد مربوط به ID مقایسه می‌شه. چون اولی عدد ۱ و دومی عدد ۰ داره در جایگاه ID، اولی برنده می‌شه؛ حتی اگه در جایگاه Class، دومی عدد بزرگ‌تری داشته باشه. یعنی رنگ نهایی نارنجی خواهد بود.

این نکته خیلی مهمه: Specificity به‌صورت رقم‌به‌رقم مقایسه می‌شه، نه با جمع کردن اعداد در یک عدد واحد. یعنی هزار Class هم نمی‌تونن روی یک ID غلبه کنن.

نقش !important در کنار Specificity

همون‌طور که در درس قبل دیدیم، !important اصلاً وارد محاسبه Specificity نمی‌شه؛ بلکه یک لایه بالاتر و جدا از Specificity عمل می‌کنه. یعنی حتی یک Type Selector ساده با !important، روی یک ID Selector بدون !important غلبه می‌کنه.

نکاتی درباره Selectorهای خاص

  • :is() و :where(): تابع :is() Specificity بالاترین آرگومان داخلش رو می‌گیره، ولی :where() همیشه Specificity صفر داره، حتی اگه آرگومان‌های پیچیده داخلش باشن. این تفاوت مهم رو در فصل ۳ با جزئیات کامل می‌بینیم.
  • Pseudo-element‌ها: مثل ::before و ::after، هم‌وزن با Type Selector محاسبه می‌شن.

چرا Specificity بالا معمولاً مشکل‌ساز می‌شه؟

وقتی از Selectorهای بیش‌ازحد اختصاصی (مثلاً ترکیب چند ID و Class تودرتو) استفاده کنی، خیلی سخت می‌شه بعداً اون استایل رو Override کرد؛ چون هر Rule جدیدی که بخواد این مقدار رو تغییر بده، باید Specificity حتی بالاتری داشته باشه. این موضوع در فصل CSS Architecture به‌عنوان یکی از دلایل اصلی «CSS غیرقابل‌نگهداری» بررسی می‌شه.

نکات مهم

  • Specificity به‌ترتیب چهار سطح محاسبه می‌شه: Inline، ID، Class/Attribute/Pseudo-class، Type/Pseudo-element.
  • مقایسه Specificity رقم‌به‌رقم انجام می‌شه، نه با جمع کردن اعداد.
  • !important کاملاً خارج از محاسبه Specificity قرار می‌گیره.

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

  • تصور اینکه تعداد بیشتر Classها می‌تونه روی یک ID غلبه کنه.
  • نوشتن Selectorهای بیش‌ازحد پیچیده و تودرتو که Specificity غیرضروری بالایی تولید می‌کنن.
  • استفاده از ID Selector فقط برای استایل‌دهی (به‌جای استفاده‌های ساختاری)، که باعث سخت شدن Override کردن استایل در آینده می‌شه.

بهترین روش‌ها

  • ترجیحاً از Class Selector به‌عنوان روش اصلی استایل‌دهی استفاده کن، نه ID.
  • Selectorها رو تا حد امکان ساده و کوتاه نگه دار.
  • به‌جای افزایش Specificity برای غلبه بر یک استایل قدیمی، ساختار CSS رو بازبینی کن.

جمع‌بندی

Specificity عددی چهاربخشی است که میزان اختصاصی بودن یک Selector را نشان می‌دهد و از چهار سطح Inline، ID، Class (و مشابه‌ها) و Type (و مشابه‌ها) تشکیل شده است. مقایسه Specificity به‌صورت رقم‌به‌رقم از چپ به راست انجام می‌شود، و این مفهوم پس از Origin و Importance، دومین عامل تعیین‌کننده در فرایند Cascade است.