UIDex

متتبّع التمرير

Scrollspy

IntersectionObserver

اسمه كمانسكرول سباي، قائمة «في هذه الصفحة»، فهرس جانبي متتبّع، محتويات الصفحة، مؤشّر القسم الحالي، روابط داخل الصفحة، on this page، in-page navigation، active section nav، page outline، anchor nav، jump links

متتبّع التمرير قائمة بعناوين مستند واحد، والرابط الذي يقابل القسم الظاهر أمام القارئ يُعلَّم فيها وحده، وينتقل التعليم إلى الرابط التالي كلّما تحرّك التمرير. وهو مكوّن من شيئين: روابط تشير إلى معرّفات داخل نفس الصفحة، ومراقب يقرّر أيّها النشط في هذه اللحظة. وهو ليس مسار تنقّل (breadcrumbs)، ولا جدول محتويات، ولا شريط تقدّم قراءة. فمسار التنقّل يصف موقع الصفحة في شجرة الموقع ولا يتغيّر ما دمت فيها، أمّا المتتبّع فلا يتكلّم عن الموقع إطلاقاً بل عن موضعك داخل مستند واحد. وجدول المحتويات هو هذه القائمة نفسها منقوصةً من سلوك التتبّع: روابطه تقفز ولا يعرف أحد أين وصلت. وشريط تقدّم القراءة يعرض نسبة متّصلة من طول المستند ولا يعطيك هدفاً تضغطه، بينما يعطيك المتتبّع اسم قسم محدّد يمكن الانتقال إليه. والفيصل بسيط: مرّر الصفحة دون أن تضغط شيئاً، فإن لم يتغيّر شيء في القائمة فما عندك جدول محتويات.

لو قلت عليه…

«القايمة اللي على جنب المقال واللي بينوّر منها العنوان اللي أنا فيه»«الفهرس اللي بيمشي معايا وأنا بنزل في الصفحة»«الروابط اللي بتوديني لجزء جوّه نفس الصفحة»«العناوين اللي بتبان على الجنب في صفحات التوثيق»«حاجة تقولّي أنا فين في الصفحة الطويلة دي»

العيّنة الحيّة

تفاعل مع الديمو. كل الأجزاء حقيقية ومرقّمة.

التثبيت

ثبّت الحزمة من مدير الحزم الذي تستعمله، ثم استوردها في نقطة الدخول.

ملفّ الإعداد

كل الخيارات لها قيم افتراضية، فابدأ بملفّ فارغ وأضف ما تحتاجه فقط.

السمات

السمة الفاتحة هي الافتراضية، والداكنة تتبع إعداد النظام.

أسئلة متكرّرة

سؤالان يتكرّران: لماذا لا يظهر العنوان؟ ولماذا يتأخّر التعليم؟

في هذه الصفحة
RTLالقائمة عند النهاية المنطقية، وخطّ التعليم بـ border-inline-start

تشريح العنصر: كل جزء واسمه

مرّر على أي سطر ليتحدّد مكانه في الديمو فوق.

برومبت البناء

ابنِ متتبّع تمرير لصفحة توثيق طويلة. ولّد لكل عنوان h2 و h3 معرّفاً ثابتاً مشتقّاً من نصّه ولا تغيّره بعد ذلك، وابنِ قائمة روابط داخل nav يحمل اسماً عبر aria-labelledby مشيراً إلى عنوان «في هذه الصفحة» المرئي، بترتيب ورود الأقسام في المستند، وكل href يشير إلى معرّف عنوان حتى يعمل الانتقال بلا JavaScript. حدّد القسم النشط بـ IntersectionObserver واحد يراقب كل العناوين، ولا تستعمل مستمع scroll ولا تقرأ getBoundingClientRect داخل مسار التمرير. اضبط rootMargin على شريط قريب من أعلى منطقة القراءة بقيمة مثل "-88px 0px -65% 0px"، حتى يتبدّل التعليم عند وصول العنوان إلى موضع القراءة لا عند ملامسته أسفل الشاشة، وعالج القسم الأخير القصير بحيث يُعلَّم عند بلوغ نهاية المستند. ضع aria-current="true" على رابط واحد فقط وأزلها عن السابق في نفس التحديث، ولا تنقل التركيز إلى الرابط الجديد إطلاقاً. أضف على العناوين scroll-margin-block-start بمقدار ارتفاع الرأس اللاصق، واجعل التمرير قفزة فورية عند تفعيل prefers-reduced-motion. ثبّت العمود بـ position: sticky مع inset-block-start وامنحه max-block-size و overflow-y: auto، وتأكّد أن لا سلف له overflow بقيمة hidden أو auto أو scroll. واستعمل الخصائص المنطقية في كل التنسيق: العمود عند النهاية المنطقية للمقال عبر مسارات grid، وخط التعليم بـ border-inline-start مرسوماً شفّافاً على كل الروابط، وتصفير حشو القائمة بـ padding-inline-start: 0 ثم إزاحة المستويات بـ padding-inline-start، ولا تكتب left ولا right ولا border-left. وافصل المراقب بـ disconnect عند تفكيك المكوّن.

سلوكه في الاتجاه من اليمين لليسار

الجزء ده حصري عندنا.

جهة العمود

ينعكس

القائمة تجلس عند النهاية المنطقية للمقال: يمين الصفحة في الإنجليزية، ويسارها في العربية. نفّذ التخطيط بـ grid-template-columns: 1fr 15rem أو بصفّ flex، فمسارات الأعمدة تُرصف على المحور المضمّن وتنعكس مع direction من تلقاء نفسها. ولا تثبّت العمود بـ position: absolute مع right: 0 ولا بـ float: right، فكلاهما يبقى على اليمين بعد الانعكاس ويجلس فوق النصّ العربي.

شريط التعليم

ينعكس

الخط الرفيع الذي يعلّم الرابط النشط يقف على الحافّة المواجهة للنصّ، فهو يسار الرابط في الإنجليزية ويمينه في العربية. اكتبه border-inline-start: 2px solid لا border-left، وارسمه على كل الروابط بلون transparent ثم لوّن النشط وحده، وإلا زحف النصّ بمقدار بكسلين كلّما تبدّل القسم. والحشو المقابل له padding-inline-start حتى تبقى المسافة بين الخط والكلمة على الجهة الصحيحة.

إزاحة المستويات المتداخلة

ينعكس

رابط h3 يُزاح للداخل تحت رابط h2 الذي يعلوه، والإزاحة على المحور المضمّن، فمكانها padding-inline-start على العنصر أو margin-inline-start على القائمة الفرعية. والفخّ في التصفير لا في الإضافة: ورقة أنماط المتصفّح تعطي ol و ul أصلاً padding-inline-start: 40px، فسطر padding-left: 0 لا يحذف منها شيئاً في العربية ويترك فجوة ٤٠ بكسل على اليمين. صفّرها بـ padding-inline-start: 0 ثم أعِد إزاحتك أنت، وإن رسمت خطّاً إرشادياً بمحاذاة القائمة الفرعية فاجعله border-inline-start عليها.

المراقب لا ينعكس

لا ينعكس

قيم rootMargin أربع قيم فيزيائية بترتيب top ثم right ثم bottom ثم left، لا تقبل كلمة منطقية واحدة ولا تتبدّل مع dir. وهذا لا يضرّ متتبّعاً رأسياً لأن العاملتين فيه هما القيمة العلوية والسفلية، فاترك الجانبيتين صفراً. ونفس الحكم على boundingClientRect داخل كل IntersectionObserverEntry: قيمتا left و right فيه إحداثيان فيزيائيان بالنسبة للشاشة، فإذا رتّبت الأقسام لتختار أعلاها فرتّبها بـ top لأنها وحدها لا تتأثّر بالاتجاه.

شريط تقدّم القراءة

ينعكس

إن وضعت شريط تقدّم فوق القائمة فهو يمتلئ من البداية المنطقية، أي من اليمين في العربية. النسبة نفسها لا علاقة لها بالاتجاه لأنها تُقرأ من scrollTop على المحور الرأسي، والذي ينعكس هو الرسم وحده. ولأن transform-origin لا تقبل أي كلمة منطقية أصلاً، فإمّا أن تحرّك inline-size من صفر إلى ١٠٠٪ على عنصر مرسى بـ inset-inline-start: 0، وإمّا أن تكتب transform-origin: right بيدك داخل [dir="rtl"].

أسماؤه في الكود

كل سطر هو كلمة مكتبة واحدة عن نفس الشيء. خد السطر اللي بيكلّم مشروعك.

HTML<a href="#install"> + <h2 id="install">الزوج الذي يجعل الانتقال يعمل قبل تحميل أي سطر JavaScript.
ARIAaria-current="true"استعمل true أو location لقسم داخل الصفحة؛ أمّا page فتعني أن الرابط يقود إلى الصفحة المعروضة نفسها.
DOMnew IntersectionObserver(cb, { rootMargin })ينادي دالّتك عند العبور فقط، فيخرج الحساب من مسار التمرير كلّه.
CSSscroll-margin-block-start: 5remيمنع الرأس اللاصق من ابتلاع العنوان بعد القفز، وهي الصيغة المنطقية لـ scroll-margin-top.
CSSposition: sticky + inset-block-startيُبقي العمود مرئياً، ويسكت تماماً داخل أي سلف له overflow بقيمة hidden أو auto أو scroll.
CSSborder-inline-startالخاصّية التي تنقل خط التعليم إلى الجهة الصحيحة حين تنعكس الصفحة.
Bootstrapdata-bs-spy="scroll"من هنا جاء الاسم؛ نسخته الحالية مبنية على IntersectionObserver وتكشف rootMargin كخيار.

شوف كمان

آخر تحديث · 2026-08-19