مرور تخصصی: first-child، nth-child() و empty در بستر واقعی

در فصل ۳ (درس ۳-۷)، با خانواده کامل Structural Selectorها آشنا شدیم: :first-child، :last-child، :nth-child()، :nth-last-child()، :nth-of-type()، :only-child و :empty. چون این فصل، به دسته‌بندی کامل Pseudo-classها اختصاص داره، این درس، سه‌تای پرکاربردترین این خانواده رو، با مثال‌های عملی‌تر و کاربردهای واقعی‌تر، دوباره مرور می‌کنه.

مرور سریع: first-child و last-child

li:first-child {
  border-top: none;
}

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

یکی از رایج‌ترین کاربردهای عملی این دو Pseudo-class، حذف حاشیه اضافه در ابتدا یا انتهای یک لیست؛ وقتی هر آیتم لیست، یک border-top برای جداسازی از آیتم قبلی داره، اولین آیتم، نیازی به این حاشیه نداره (چون چیزی قبلش نیست).

یک کاربرد بسیار رایج: خط جداکننده بین آیتم‌ها (نه دور همه)

.list-item {
  padding: 12px 0;
  border-bottom: 1px solid #eee;
}

.list-item:last-child {
  border-bottom: none;
}
<div class="list-item">آیتم اول</div>
<div class="list-item">آیتم دوم</div>
<div class="list-item">آیتم سوم</div>

در این مثال، هر آیتم، یک خط جداکننده زیرش داره؛ ولی آیتم آخر، چون چیزی بعدش نیست، این خط رو نداره. نتیجه، ظاهریه که دقیقاً شبیه یک لیست با «جداکننده بین آیتم‌ها»ست، نه یک بوردر دور تک‌تک عناصر.

nth-child(): فراتر از even/odd

tr:nth-child(3n) {
  background-color: #f0f8ff;
}

همون‌طور که در فصل ۳ دیدیم، فرمول an+b، امکانات فراتر از فقط زوج/فردی می‌ده. این مثال، هر سومین ردیف رو (ردیف‌های ۳، ۶، ۹ و به همین ترتیب) هدف می‌گیره؛ کاربردی برای جداول بزرگ که نیاز به گروه‌بندی بصری هر چند ردیف دارن.

یک کاربرد خلاقانه: انتخاب یک بازه مشخص با فرمول ترکیبی

li:nth-child(n+3):nth-child(-n+6) {
  background-color: lightyellow;
}
<ul>
  <li>۱</li>
  <li>۲</li>
  <li>۳ (رنگی)</li>
  <li>۴ (رنگی)</li>
  <li>۵ (رنگی)</li>
  <li>۶ (رنگی)</li>
  <li>۷</li>
</ul>

ترکیب دو :nth-child() پشت‌سرهم (که هردو باید هم‌زمان صادق باشن)، امکان انتخاب یک بازه دقیق رو می‌ده. nth-child(n+3) یعنی «از آیتم سوم به بعد»؛ و nth-child(-n+6) یعنی «تا آیتم ششم». ترکیب این دو، دقیقاً آیتم‌های سوم تا ششم رو هدف می‌گیره؛ یک تکنیک قدرتمند برای موقعیت‌هایی که فقط یک بخش میانی از یک لیست، نیاز به استایل خاص داره.

empty: هدف قرار دادن عناصر کاملاً خالی

p:empty {
  display: none;
}

همون‌طور که در فصل ۳ دیدیم، :empty، فقط عناصری رو انتخاب می‌کنه که هیچ محتوایی (نه متن، نه فرزند، حتی نه یک فاصله خالی) نداشته باشن.

یک نکته ظریف: فاصله خالی، یعنی دیگر :empty نیست

div:empty {
  border: 2px dashed red;
}
<div></div>  <!-- این :empty است -->
<div> </div> <!-- این :empty نیست، چون یک فاصله (space) دارد -->

یک نکته فنی مهم که در فصل ۳ کمتر بهش پرداختیم: حتی یک تک فاصله خالی (space) داخل یک عنصر، کافیه که اون رو از حالت :empty خارج کنه؛ چون از نظر مرورگر، اون فاصله، خودش یک نوع «محتوای متنی» محسوبه، حتی اگه از نظر بصری، هیچ چیزی دیده نشه.

یک کاربرد عملی: مخفی کردن باکس‌های نتیجه جست‌وجوی خالی

.search-results {
  border: 1px solid #ccc;
  padding: 12px;
}

.search-results:empty {
  display: none;
}
<div class="search-results">
  <!-- وقتی جاوااسکریپت اینجا محتوایی اضافه نکرده باشد، این باکس کاملاً خالی است -->
</div>

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

ترکیب only-child با first-child برای منطق دقیق‌تر

li:only-child {
  list-style: none;
}

یادآوری از فصل ۳: :only-child، فقط عنصری رو هدف می‌گیره که تنها فرزند والدشه (بدون هیچ Sibling دیگه‌ای). این مثال، اگه یک لیست فقط یک آیتم داشته باشه، نشانگر لیست (Bullet یا شماره) رو حذف می‌کنه؛ چون معمولاً نشون دادن یک نشانگر لیست، برای یک آیتم تنها، از نظر بصری معنای چندانی نداره.

یک مثال کامل و ترکیبی: کارت‌های محصول با گروه‌بندی خودکار

.product-card {
  border-bottom: 1px solid #eee;
  padding: 16px 0;
}

.product-card:last-child {
  border-bottom: none;
}

.product-card:nth-child(odd) {
  background-color: #fafafa;
}

.empty-message {
  display: none;
}

.product-list:empty + .empty-message {
  display: block;
}

در این مثال، هر کارت محصول، یک خط جداکننده داره (به‌جز آخری)، ردیف‌های فرد، رنگ پس‌زمینه ملایمی می‌گیرن (Zebra Striping)، و اگه کل لیست محصولات، کاملاً خالی باشه (با :empty)، یک پیام «موردی یافت نشد» (که با Sibling Combinator از فصل ۳ هدف قرار گرفته)، نمایش داده می‌شه. این ترکیب، نشون می‌ده چطور چند Structural Selector، می‌تونن، بدون هیچ جاوااسکریپتی، منطق نمایشی کاملاً پویایی بسازن.

نکات مهم

  • ترکیب دو :nth-child() پشت‌سرهم (مثل nth-child(n+3):nth-child(-n+6))، امکان انتخاب یک بازه دقیق از آیتم‌ها را می‌دهد.
  • حتی یک تک فاصله خالی (space) داخل یک عنصر، آن را از حالت :empty خارج می‌کند.
  • :empty، ابزاری کاربردی برای مخفی کردن خودکار عناصری است که هنوز، معمولاً توسط جاوااسکریپت، محتوایی دریافت نکرده‌اند.

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

  • تصور اینکه یک عنصر با فاصله خالی داخلش، همچنان :empty محسوب می‌شود.
  • استفاده نادرست از فرمول‌های nth-child() برای انتخاب بازه، بدون درک درست از منطق ترکیب دو شرط هم‌زمان.
  • فراموش کردن last-child هنگام افزودن خط جداکننده بین آیتم‌های یک لیست، که باعث یک خط اضافه و بی‌مورد در انتهای لیست می‌شود.

جمع‌بندی

first-child و last-child، برای مدیریت لبه‌های ابتدایی و انتهایی یک مجموعه (مثل حذف خط جداکننده آخرین آیتم) بسیار کاربردی هستند. nth-child()، با ترکیب دو شرط پشت‌سرهم، امکان انتخاب یک بازه دقیق از آیتم‌ها را فراهم می‌کند، و :empty، با دقت به این نکته که حتی یک فاصله خالی هم آن را غیرفعال می‌کند، ابزاری قدرتمند برای مدیریت خودکار محتوای پویا و خالی است.