التمرير اللانهائي
Infinite ScrollIntersectionObserver
اسمه كمانسكرول لانهائي، انفينيت سكرول، التمرير المتواصل، التحميل عند التمرير، القائمة اللانهائية، الخلاصة المتواصلة، endless scroll، continuous scroll، infinite list، auto load on scroll، endless feed، scroll pagination
التمرير اللانهائي أسلوب لعرض قائمة طويلة: كلما اقترب المستخدم من آخر ما هو معروض بدأ طلب الدفعة التالية، وتُلحَق الدفعة بما قبلها في نفس الصفحة. والشرط الذي يميّزه أن موضع التمرير هو ما يطلق الطلب، فلا يوجد قرار صريح من المستخدم بتحميل المزيد. وهو ليس ترقيم صفحات، لأن الترقيم يمنح كل شريحة عنواناً ثابتاً مثل ?page=7 ويستبدل المحتوى استبدالاً كاملاً فيبقى حجم الصفحة كما هو، بينما هنا تتراكم العناصر في DOM واحد بلا سقف وبلا عنوان يعود إليه أحد. وهو ليس زرّ «تحميل المزيد» كذلك، فالميكانيكا واحدة (نفس الطلب، ونفس الإلحاق أسفل القائمة)، والفرق الوحيد أن الزرّ ينتظر ضغطة، وهذه الضغطة وحدها تحلّ أغلب مشاكل الوصولية التي يخلقها التحميل التلقائي. وهو ليس القائمة الافتراضية (virtualization)، فتلك تقنية رسم تُبقي في DOM ما يقع قرب النافذة وحده، وتصلح كذلك لبيانات محمّلة بالكامل، والاثنان يُجمعان عادةً لأن تمريراً لانهائياً بلا تدوير للعناصر يخنق الصفحة بعد بضع دفعات. وقبل أن تختاره اسأل: هل سيحتاج أحد أن يرسل رابطاً لعنصر بعينه، وهل يوجد تحت القائمة شيء يحتاجه المستخدم؟ إن كان الجواب نعم في أيّهما فالترقيم أو الزرّ هو ما تريده.
لو قلت عليه…
العيّنة الحيّة
تفاعل مع الديمو. كل الأجزاء حقيقية ومرقّمة.
المعروض ٦ من ١٢
تشريح العنصر: كل جزء واسمه
مرّر على أي سطر ليتحدّد مكانه في الديمو فوق.
برومبت البناء
سلوكه في الاتجاه من اليمين لليسار
الجزء ده حصري عندنا.
أي محور ينعكس أصلاً
لا ينعكسالخلاصة الرأسية لا تنعكس: اتجاه الصفحة يحكم المحور المضمّن (الأفقي)، والتمرير هنا يجري على المحور الكتلي، فترتيب الصفوف واتجاه نموّ القائمة واحد في العربية والإنجليزية. والمصيدة الوحيدة هي rootMargin في IntersectionObserver، فهو قيمة فيزيائية بحتة تُكتب بترتيب هوامش CSS (أعلى، يمين، أسفل، يسار) ولا تقبل أي كلمة منطقية. القائمة الرأسية تعنيها القيمة الثالثة وحدها وهي نفسها في الاتجاهين، أما القائمة الأفقية فتحتاج القيمة الثانية في LTR والرابعة في RTL، فاحسبها من direction بدل كتابتها ثابتة.
المؤشّر الدوّار والصفوف الهيكلية
لا ينعكسالمؤشّر الدوّار لا يُقلب أبداً: قاعدة شاملة مثل [dir="rtl"] svg { transform: scaleX(-1) } تعكس اتجاه دورانه فيبدو وكأنه يدور إلى الخلف. الذي ينعكس هو موضعه فقط، فثبّته بـ inset-inline-end إن كان معلّقاً في ركن، أو ضعه في صفّ flex واترك المحور المضمّن يتكفّل به. والصفوف الهيكلية التي تلمع بـ linear-gradient(to right, …) تحتاج تدخّلاً يدوياً، لأن التدرّجات لا تعرف الكلمات المنطقية: اللمعة تسير عكس اتجاه القراءة في العربية ما لم تقلبها إلى to left داخل [dir="rtl"].
عدّاد العناصر
لا ينعكسالرقم نفسه لا ينقلب: خوارزمية Unicode ثنائية الاتجاه تصنّف الأرقام ضمن EN و AN وتُبقيها تُقرأ من اليسار إلى اليمين داخل نصّ عربي، فـ«٦٠ من ٣٤٨» تحتفظ بترتيبها الداخلي بلا أي تدخّل منك. القرار الوحيد المطلوب هو نظام الأرقام، والالتزام به في كل موضع: new Intl.NumberFormat("ar-EG").format(348) يعطيك ٣٤٨ بالأرقام العربية الهندية، وإضافة -u-nu-latn إلى الوسم تعطيك 348 بالأرقام اللاتينية. ولا تخلط النظامين في شاشة واحدة، فعدّاد بالهندية فوق أرقام صفوف باللاتينية يجعل المستخدم يظنّ أنهما يعدّان شيئين مختلفين.
القائمة الأفقية
ينعكسفي التمرير اللانهائي الأفقي تنتقل نهاية القائمة إلى اليسار في العربية، وينتقل معها عنصر الاستشعار. ولا تحسب النهاية بـ scrollLeft + clientWidth >= scrollWidth: المتصفّحات الحديثة (Chrome و Firefox و Safari) توافقت على نموذج واحد يجعل scrollLeft صفراً عند البداية المنطقية ثم يصبح سالباً كلما تقدّم المستخدم نحو النهاية في RTL، فالشرط لا يتحقّق أبداً، وإن اضطررت إلى الحساب فاستعمل Math.abs(el.scrollLeft). والأنظف أن تتخلّى عن الحساب أصلاً: اجعل عنصر الاستشعار آخر عقدة في DOM ودع IntersectionObserver يقرّر، لأن ترتيب DOM هو الترتيب المنطقي في الاتجاهين، ولأن flex-direction: row يضع أول عنصر عند البداية المنطقية وحده بلا row-reverse.
اتجاه نصّ العناصر الواردة
لا ينعكسمحتوى الخلاصة يصل من الخادم مختلطاً: منشور عربي، ثم اسم مستودع بالإنجليزية، ثم سطر يبدأ برقم. جهة الصفّ تُحسم من الصفّ نفسه لا من الصفحة، فاضبط dir="auto" على العنصر النصّي داخل كل صفّ لا على القائمة كلها، وحاذِ بـ text-align: start لا بـ text-align: right حتى تتبع المحاذاة الجهة التي حُسمت. وانعكاس الصفحة لا يغيّر شيئاً في صفّ لاتيني، وهذا هو المقصود، ولو تركت القرار للحاوية وحدها ظهرت النقطة والقوسان في الطرف الخطأ من كل سطر لاتيني.
أسماؤه في الكود
كل سطر هو كلمة مكتبة واحدة عن نفس الشيء. خد السطر اللي بيكلّم مشروعك.
شوف كمان
آخر تحديث · 2026-08-19