انتخاب بر اساس جایگاه در ساختار: Structural Selectors

در درس Pseudo-class به‌طور مختصر با :first-child و :last-child آشنا شدیم. حالا وقتشه این خانواده رو کامل و دقیق بررسی کنیم؛ Selectorهایی که بر اساس جایگاه دقیق یک عنصر در میان Siblingهاش عمل می‌کنن، بدون نیاز به هیچ Class یا ID اضافه‌ای.

چرا اصلاً به Structural Selector نیاز داریم؟

فرض کن می‌خوای فقط ردیف‌های زوج یک جدول رنگ متفاوتی داشته باشن. بدون Structural Selector، مجبور بودی به هر ردیف زوج، دستی یک Class اضافه کنی. با این Selectorها، می‌شه این کار رو کاملاً خودکار و بدون دست‌زدن به HTML انجام داد.

first-child و last-child (مرور و تکمیل)

li:first-child {
  font-weight: bold;
}

li:last-child {
  border-bottom: none;
}

همون‌طور که قبلاً دیدیم، این دو فقط اولین و آخرین فرزند والد رو هدف می‌گیرن؛ صرف‌نظر از نوع تگ اون‌ها، به شرطی که خودشون li باشن.

nth-child(): قدرتمندترین ابزار این خانواده

:nth-child() اجازه می‌ده هر فرزندی رو بر اساس یک فرمول یا عدد مشخص، در میان تمام Siblingهاش (بدون توجه به نوع تگ)، انتخاب کنی.

انتخاب یک فرزند مشخص با عدد

li:nth-child(3) {
  color: crimson;
}
<ul>
  <li>آیتم ۱</li>
  <li>آیتم ۲</li>
  <li>آیتم ۳ (این قرمز می‌شود)</li>
  <li>آیتم ۴</li>
</ul>

این Selector فقط سومین li رو، از میان کل Siblingها، انتخاب می‌کنه.

انتخاب ردیف‌های زوج و فرد

tr:nth-child(even) {
  background-color: #f5f5f5;
}

tr:nth-child(odd) {
  background-color: #ffffff;
}

کلیدواژه‌های even و odd دقیقاً همون معنای فارسی‌شون رو دارن: زوج و فرد. این ترکیب یکی از رایج‌ترین کاربردهای :nth-child() برای رنگی کردن متناوب ردیف‌های جدوله (Zebra Striping).

استفاده از فرمول‌های ریاضی

li:nth-child(3n) {
  border-left: 3px solid teal;
}

این Selector هر سومین عنصر رو انتخاب می‌کنه (یعنی ۳، ۶، ۹ و به همین ترتیب). فرمول an+b در :nth-child()، امکان ساخت الگوهای متنوع رو فراهم می‌کنه؛ n از صفر شروع شده و به‌ترتیب افزایش پیدا می‌کنه.

li:nth-child(3n + 1) {
  color: navy;
}

این Selector عناصر شماره ۱، ۴، ۷، ۱۰ و به همین ترتیب رو انتخاب می‌کنه (چون با جایگذاری n=0,1,2,... در فرمول 3n+1 به این اعداد می‌رسیم).

nth-last-child(): شمارش از انتها

li:nth-last-child(2) {
  color: orange;
}

این Selector دقیقاً مثل :nth-child() عمل می‌کنه، ولی شمارش رو از آخرین فرزند شروع می‌کنه، نه از اولی. یعنی در این مثال، ماقبل‌آخرین li انتخاب می‌شه.

nth-of-type() و nth-last-of-type(): محدود کردن به نوع تگ

یکی از محدودیت‌های :nth-child() اینه که نوع تگ رو در نظر نمی‌گیره؛ فقط جایگاه کلی رو در میان همه Siblingها می‌شماره، حتی اگه اون Siblingها انواع مختلفی از تگ باشن. برای حل این مشکل، :nth-of-type() وجود داره:

p:nth-of-type(2) {
  font-style: italic;
}
<h2>عنوان</h2>
<p>پاراگراف اول</p>
<p>پاراگراف دوم (این ایتالیک می‌شود)</p>
<p>پاراگراف سوم</p>

در این مثال، :nth-of-type(2) فقط بین تگ‌های p شمارش می‌کنه (نه بین همه Siblingها)؛ یعنی h2 اصلاً وارد شمارش نمی‌شه. برای همین دومین پاراگراف انتخاب می‌شه، حتی با اینکه یک h2 قبل از این پاراگراف‌ها اومده.

تفاوت کلیدی nth-child و nth-of-type

p:nth-child(2) {
  color: red;
}

p:nth-of-type(2) {
  color: blue;
}
<h2>عنوان</h2>
<p>این پاراگراف اول است</p>
<p>این پاراگراف دوم است</p>

اینجا خیلی مهمه که دقت کنیم: p:nth-child(2) اصلاً چیزی رو انتخاب نمی‌کنه؛ چون دومین فرزند این والد، همون p اول نیست بلکه یک h2 است (که خودش اولین فرزنده)، پس هیچ pای جایگاه دوم رو نداره. اما p:nth-of-type(2) فقط بین تگ‌های p می‌شمره، پس دومین پاراگراف (که خودش سومین فرزند کلیه) رو به‌درستی پیدا می‌کنه و آبی می‌کنه.

only-child و only-of-type

p:only-child {
  font-size: 20px;
}

:only-child فقط عنصری رو انتخاب می‌کنه که تنها فرزند والدشه؛ یعنی هیچ Sibling دیگه‌ای نداشته باشه. :only-of-type هم مشابهه، ولی فقط بین تگ‌های هم‌نوع بررسی می‌کنه.

empty: عناصر کاملاً خالی

p:empty {
  display: none;
}

:empty عنصری رو انتخاب می‌کنه که هیچ محتوایی نداره؛ نه متن، نه حتی فاصله خالی، و نه هیچ عنصر فرزندی. این Selector معمولاً برای مخفی کردن عناصر خالی (مثلاً یک پاراگراف که به‌اشتباه بدون محتوا رندر شده) استفاده می‌شه.

جدول جمع‌بندی

Selector عملکرد
:first-child اولین فرزند والد
:last-child آخرین فرزند والد
:nth-child(n) فرزند n‌ام، بین همه Siblingها (بدون توجه به نوع تگ)
:nth-last-child(n) مثل nth-child ولی شمارش از انتها
:nth-of-type(n) فرزند n‌ام، فقط بین تگ‌های هم‌نوع
:only-child تنها فرزند والد (بدون هیچ Sibling)
:empty عنصر بدون هیچ محتوا یا فرزند

نکات مهم

  • :nth-child() بین همه Siblingها شمارش می‌کنه، بدون توجه به نوع تگ؛ :nth-of-type() فقط بین تگ‌های هم‌نوع.
  • شمارش در این فرمول‌ها همیشه از عدد ۱ شروع می‌شه، نه صفر.
  • فرمول an+b امکان ساخت الگوهای تکرارشونده (مثل هر سومین عنصر) رو فراهم می‌کنه.

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

  • استفاده از :nth-child() در حالتی که واقعاً منظور «فرزند n‌ام از نوع خاص» بوده، در حالی که :nth-of-type() انتخاب درستی بود.
  • فراموش کردن اینکه شمارش از ۱ شروع می‌شه، نه ۰.
  • گیج شدن بین :nth-child(even) که یک کلیدواژه ساده‌ست، و فرمول‌های عددی مثل 2n.

جمع‌بندی

Structural Selectorها امکان انتخاب عناصر بر اساس جایگاه دقیق‌شون در میان Siblingها رو، بدون نیاز به هیچ Class اضافه‌ای، فراهم می‌کنن. :nth-child() شمارش رو بین همه Siblingها انجام می‌ده، در حالی که :nth-of-type() فقط بین تگ‌های هم‌نوع می‌شمره؛ این تفاوت، مهم‌ترین نکته‌ای‌ست که باید در استفاده از این Selectorها در نظر گرفت.