ترقيم الصفحات
Pagination<nav aria-label="pagination">
اسمه كمانباچينيشن، باجينيشن، شريط الصفحات، أرقام الصفحات، التنقّل بين الصفحات، مؤشّر النقاط، pager، paging، page navigation، paginator، page numbers، dot indicator
ترقيم الصفحات منطقة تنقّل تقسّم مجموعة واحدة كبيرة (نتائج بحث، جدول طلبات، أرشيف مقالات) إلى شرائح متساوية، وتمنح كل شريحة عنواناً خاصاً بها. والفائدة في هذا العنوان: الصفحة السابعة لها رابط مثل ?page=7 تنسخه وترسله لزميلك، وتحفظه في المفضّلة، ويفهرسه محرّك البحث، وتعود إليه بعد أسبوع فتجد نفس الموضع. وهو ليس مؤشّر خطوات، لأن الخطوات رحلة مرتّبة لها نهاية تُنجَز عندها المهمّة، أمّا الصفحات فشرائح متكافئة تقفز بينها بأي ترتيب ولا شيء «يكتمل» في آخرها. والتمرير اللانهائي (infinite scroll) شيء آخر، فهو يلغي من الأساس فكرة الموضع الذي يملك عنواناً: لا رقم ولا رابط ولا طريق للرجوع إلى نتيجة رأيتها أمس إلا بإعادة التمرير من البداية. أمّا زرّ «تحميل المزيد» فالفرق بينه وبين الترقيم ميكانيكي لا ذوقي: الزرّ يُلحِق الدفعة الجديدة أسفل القديمة فينمو الـ DOM بلا سقف، بينما ترقيم الصفحات يستبدل المحتوى استبدالاً كاملاً فيبقى حجم الصفحة ثابتاً مهما تعمّق المستخدم. والقاعدة العملية: لو احتاج المستخدم يوماً أن يقول «أنا في الصفحة الرابعة» أو أن يعود إليها لاحقاً، فالترقيم وحده من بين الثلاثة يقدر على ذلك.
لو قلت عليه…
العيّنة الحيّة
تفاعل مع الديمو. كل الأجزاء حقيقية ومرقّمة.
تشريح العنصر: كل جزء واسمه
مرّر على أي سطر ليتحدّد مكانه في الديمو فوق.
برومبت البناء
سلوكه في الاتجاه من اليمين لليسار
الجزء ده حصري عندنا.
اتجاه صفّ الأرقام
ينعكسالصفّ كله ينعكس: الصفحة ١ تجلس في أقصى اليمين، والأخيرة عند اليسار، وسهم «التالي» ينتهي على الطرف الأيسر. وحاوية flex-direction: row تفعل هذا وحدها لأن المحور المضمّن يتبع direction، فلا تضف row-reverse داخل [dir="rtl"] فهو انعكاس فوق انعكاس يعيد الصفحة ١ إلى اليسار. وللمحاذاة فخّ مشابه: justify-content: flex-start قيمة منطقية تتبع الاتجاه، بينما justify-content: left قيمة فيزيائية تلتصق بالحافّة اليسرى في اللغتين.
سهما السابق والتالي
ينعكسالسهمان أيقونتان اتجاهيتان بالمعنى الحرفي: «السابق» يجب أن يشير يميناً في العربية و«التالي» يساراً، لأنهما يشيران إلى موضع الصفحة على الشاشة لا إلى معنى مجرّد. أيقونة SVG لا تعرف شيئاً عن bidi فاعكسها صراحة بـ [dir="rtl"] .chevron { transform: scaleX(-1) }. والخطأ المقابل أسوأ: لا تبدّل ترتيب الزرّين في الـ DOM، فالانعكاس بصري تتكفّل به direction، وتبديل الترتيب يدوياً يقلبهما مرّتين فيعودان لمكانهما ويصير Tab يمرّ على «التالي» قبل «السابق».
الأرقام والفاصل بينها
لا ينعكسمحارف الأرقام نفسها لا تنعكس أبداً، لكن المحرف المحايد بينها ينعكس: داخل فقرة عربية تأخذ الشرطة في «١٢١–١٤٠» اتجاه ما حولها فيُعرض النطاق «١٤٠–١٢١»، ويقرأ المستخدم عدّاً مقلوباً في سطر «عرض ١٢١–١٤٠ من ٣٤٩». و<bdi> لا ينقذك هنا إلا مع الأرقام اللاتينية، لأن القاعدة W7 تُعيد تصنيفها حرفاً قوياً داخل عزلة لاتينية، أمّا الأرقام الهندية فصنفها AN ولا تغيّره العزلة فيبقى النطاق مقلوباً؛ فضع LRM (U+200E) على جانبَي الشرطة، أو unicode-bidi: bidi-override مع direction: ltr على النطاق وحده، أو اكتبها «من ١٢١ إلى ١٤٠» فتتخلّص من المحايد أصلاً. واختر نظاماً رقمياً واحداً للمنطقة كلها، هندياً ١ ٢ ٣ أو لاتينياً 1 2 3، ولا تكتب أبداً «صفحة ٣ من 18». وتبقى القيمة في الرابط لاتينية دائماً: ?page=٣ ليس رقماً عند الخادم و Number("٣") تُرجع NaN، فنسّق النصّ المعروض بـ Intl.NumberFormat("ar-EG") وأرسل القيمة كما هي.
مفاتيح الأسهم
ينعكسحدث keydown يسلّمك مفتاحاً فيزيائياً: ArrowRight يبقى ArrowRight مهما كان اتجاه الصفحة، والمتصفّح لا يعكسه نيابةً عنك. لكن المستخدم العربي ينتظر أن يأخذه السهم الأيمن إلى الصفحة السابقة والأيسر إلى التالية، على عكس الإنجليزية تماماً. وهذا ما توجبه مواصفة WAI-ARIA لكل عنصر مركّب في RTL. اقرأ الاتجاه من العنصر نفسه بـ el.matches(":dir(rtl)") أو getComputedStyle(el).direction، واضرب مقدار الخطوة في -1 عند rtl، ولا تربط «الصفحة التالية» بـ ArrowRight ربطاً مباشراً في الكود.
نقاط الكاروسيل والتمرير
ينعكسصفّ النقاط ينعكس مثل الأرقام: نقطة الشريحة الأولى في اليمين. والتخطيط سليم، لكن الحساب هو الذي ينكسر: داخل حاوية تمرير RTL تبدأ scrollLeft من صفر عند أقصى اليمين وتصير سالبة كلما تقدّمت، فمعادلة Math.round(el.scrollLeft / slideWidth) تعطي فهرساً سالباً وتُضيء النقطة الخطأ؛ صوابها Math.round(Math.abs(el.scrollLeft) / slideWidth). وللانتقال استخدم slide.scrollIntoView({ inline: "start" }) أو scroll-snap-align: start فكلاهما منطقي ويتبع الاتجاه، بخلاف شريط يُحرَّك بـ translateX(-100% * i) الذي يجب أن تنقلب إشارته في RTL.
أسماؤه في الكود
كل سطر هو كلمة مكتبة واحدة عن نفس الشيء. خد السطر اللي بيكلّم مشروعك.
شوف كمان
آخر تحديث · 2026-08-19