تخطَّ إلى المحتوى

🟦 شرح CSS

sibling-index() و sibling-count(): عدّ الإخوة في CSS

الدرس 29 من 30· ⏱ 4 دقائق قراءة

المشكلة التي تحلّها

بنيت قائمة عناصر وأردت أن تظهر كل واحدة بعد التي قبلها بفارق زمني بسيط — حركة متدرّجة (Staggered) تعطي إحساسًا احترافيًا بدل ظهور الكل دفعة واحدة. المشكلة أن CSS لم يكن يعرف "أنا العنصر الثالث من بين سبعة" — فكان الحل التقليدي أحد أمرين:

  1. جافاسكربت يحسب فهرس كل عنصر بنفسه ويكتب animation-delay كخاصية مضمّنة (inline style) لكل واحد.
  2. سلسلة :nth-child() يدوية تكرّر نفس القاعدة بقيمة تأخير مختلفة لكل رقم — تعمل، لكنها تنكسر أول ما يتغيّر عدد العناصر، وتحتاج تعديلًا يدويًا في كل مرة.

sibling-index() وsibling-count() تحلّان المشكلة من داخل CSS نفسه: تعطيك ترتيب العنصر بين إخوته وعددهم الكلي كقيمتين حيّتين تستخدمهما في أي حساب calc().

الصياغة

li {
  animation: fade-in 0.4s ease both;
  animation-delay: calc(sibling-index() * 100ms);
}
  • sibling-index(): تُرجع رقم ترتيب العنصر الحالي بين إخوته المباشرين (أبناء نفس الأب)، بادئة من 1 — تمامًا كـ :nth-child()، لا من صفر.
  • sibling-count(): تُرجع العدد الكلي لإخوة العنصر (بما فيه هو نفسه) — أي عدد أبناء الأب مجتمعين.

كلتاهما بلا وسائط (parentheses فارغة)، وتُعاد حساب قيمتهما تلقائيًا كلما تغيّر عدد العناصر — أضف عنصرًا سابعًا للقائمة، وكل شيء يُعاد ترقيمه وحده بلا لمس أي سطر CSS.

مثال: قائمة تظهر عناصرها بالتتابع

@keyframes fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.list li {
  animation: fade-up 0.35s ease both;
  animation-delay: calc((sibling-index() - 1) * 80ms);
}

هنا طرحنا 1 من sibling-index() ليبدأ أول عنصر بتأخير صفري (بدل 80ms) — نفس منطق التحويل من ترقيم يبدأ من 1 إلى تأخير يبدأ من 0 الذي كنت تكتبه يدويًا سابقًا لكل عنصر على حدة.

دمج الدالتين: تدرّج بالاتجاه المعاكس

sibling-count() تفتح إمكانية حسابات أعقد — كعكس اتجاه التدرّج فيبدأ آخر عنصر أولًا:

.list li {
  animation-delay: calc((sibling-count() - sibling-index()) * 80ms);
}

العنصر الأخير (الذي sibling-index() له يساوي sibling-count()) يحصل على تأخير صفري ويظهر أولًا، بينما الأول يحصل على أطول تأخير — بلا أي معرفة مسبقة بعدد العناصر وقت كتابة القاعدة.

لماذا هذا أفضل من سلسلة :nth-child()

/* الأسلوب التقليدي — يحتاج سطرًا لكل رقم، وينكسر بعد آخر رقم مكتوب */
li:nth-child(1) { animation-delay: 0ms; }
li:nth-child(2) { animation-delay: 100ms; }
li:nth-child(3) { animation-delay: 200ms; }
/* ... ماذا لو أصبحت القائمة 12 عنصرًا؟ */

مقابل سطر واحد ثابت لا يهتم بعدد العناصر:

li { animation-delay: calc((sibling-index() - 1) * 100ms); }
سلسلة :nth-child()sibling-index()
يحتاج معرفة العدد مسبقًانعم — سطر لكل رقملا
يتكيّف مع عدد متغيّرلا، ينكسر بصمتنعم تلقائيًا
صيغة الحسابمتكررة لكل رقممعادلة واحدة عامة

دعم المتصفحات لا يزال جزئيًا

هذه دوال حديثة جدًا: مدعومة في Chrome وEdge (بدءًا من الإصدار 138) وSafari (بدءًا من 26.2)، لكن Firefox لم يدعمها بعد حتى وقت كتابة هذا الدرس — لذا لا تُحسب بعد ضمن "Baseline" المتاحة على كل المتصفحات دفعة واحدة.

🔑 لمشروع يستهدف Firefox أيضًا، لفّ استخدامها بـ @supports (animation-delay: sibling-index()) ووفّر تأخيرًا ثابتًا أو بلا تأخير كبديل احتياطي — بدل الاعتماد عليها وحدها.

li { animation-delay: 0ms; } /* بديل احتياطي لكل المتصفحات */

@supports (animation-delay: sibling-index()) {
  li { animation-delay: calc((sibling-index() - 1) * 80ms); }
}

الأخطاء الشائعة

  • ❌ توقّع أن sibling-index() تبدأ من صفر → تبدأ من 1 مثل :nth-child()؛ اطرح 1 إن أردت تأخيرًا صفريًا للعنصر الأول.
  • ❌ استخدامها بلا بديل احتياطي في مشروع يدعم Firefox → التأخيرات كلها تُهمَل بصمت (القيمة غير المفهومة تُتجاهل) فتظهر كل العناصر دفعة واحدة بلا حركة متدرّجة.
  • ❌ الخلط بينها وبين :nth-child():nth-child() محدّد يُطابق عنصرًا بعينه، بينما sibling-index()/sibling-count() دالتا قيمة تُستخدمان داخل أي خاصية تقبل رقمًا عبر calc()، ليس فقط للتحديد.

خلاصة

sibling-index() وsibling-count() يعطيان CSS وعيًا بترتيب العنصر بين إخوته وعددهم الكلي، فتحوّلان حركات القوائم المتدرّجة من كود جافاسكربت أو سلاسل :nth-child() هشّة إلى معادلة calc() واحدة تتكيّف تلقائيًا مع أي عدد عناصر. لكن ضع لها بديلًا احتياطيًا عبر @supports حتى تصل لدعم Firefox.

شرح sibling-index() و sibling-count(): عدّ الإخوة في CSS — CSS بالعربي
sibling-index() و sibling-count(): عدّ الإخوة في CSSCSS بالعربي · The Code Fix

📚 لمزيد من التعمّق في CSS، راجِع توثيق CSS على MDN.

هل كان هذا الدرس مفيدًا؟