الخطوات
-
1
جعل الرأس ثابتاً باستخدام CSS
position: stickyيُبقي الرأس ضمن تدفق المستند (على عكسfixed) ويثبّته أعلى نافذة العرض بمجرد أن يتجاوزه المستخدم أثناء التمرير.z-index: 50يضمن ظهوره فوق محتوى الصفحة.css.site-header { position: sticky; top: 0; z-index: 50; background: #fff; /* optional: soften the edge between header and content */ box-shadow: 0 1px 0 rgb(0 0 0 / .06); } -
2
تعريف الحالة المخفية بكلاس CSS
استخدم كلاس
.is-hiddenيُزيح الرأس خارج نطاق العرض بـtransform: translateY(-100%). الحركة المعتمدة على Transform تُعالَج بالـ GPU — لا تُشغّل إعادة حساب التخطيط وتبقى سلسة عند 60 إطاراً في الثانية حتى على الأجهزة المتوسطة.css.site-header { position: sticky; top: 0; z-index: 50; background: #fff; transition: transform 0.3s ease, box-shadow 0.3s ease; } .site-header.is-hidden { transform: translateY(-100%); } -
3
تتبع اتجاه التمرير في JavaScript
احفظ موضع التمرير السابق في
lastScrollY. عند كل حدث تمرير، قارن قيمةwindow.scrollYالحالية بها. التمرير للأسفل يعني أن القيمة الجديدة أكبر؛ والتمرير للأعلى يعني أنها أصغر.javascriptconst header = document.querySelector('.site-header'); let lastScrollY = window.scrollY; window.addEventListener('scroll', () => { const currentScrollY = window.scrollY; const scrollingDown = currentScrollY > lastScrollY; header.classList.toggle('is-hidden', scrollingDown); lastScrollY = currentScrollY; }, { passive: true }); -
4
إضافة حدّ تمرير لمنع الوميض
قرب أعلى الصفحة، قد يتسبب الاهتزاز البسيط في التمرير بوميض الرأس ظهوراً واختفاءً. اخفِ الرأس فقط بعد أن يتجاوز المستخدم حدّاً معيناً (مثلاً ارتفاع الرأس نفسه).
javascriptconst header = document.querySelector('.site-header'); const THRESHOLD = header.offsetHeight; let lastScrollY = window.scrollY; window.addEventListener('scroll', () => { const currentScrollY = window.scrollY; // Never hide the header when near the top if (currentScrollY < THRESHOLD) { header.classList.remove('is-hidden'); lastScrollY = currentScrollY; return; } const scrollingDown = currentScrollY > lastScrollY; header.classList.toggle('is-hidden', scrollingDown); lastScrollY = currentScrollY; }, { passive: true }); -
5
تقليص حجم الرأس عند التمرير بـ CSS
نمط مكمّل: تقليص الـ padding للرأس (وحجم الشعار اختياراً) حين يمرر المستخدم للأسفل، لاستعادة بعض البكسلات مع إبقاء الرأس مرئياً. بدلاً من إخفائه كلياً، بدّل كلاس
.is-scrolled.css.site-header { position: sticky; top: 0; z-index: 50; padding-block: 1.25rem; transition: padding 0.3s ease, box-shadow 0.3s ease; } .site-header.is-scrolled { padding-block: 0.5rem; box-shadow: 0 2px 12px rgb(0 0 0 / .1); } -
6
استكشاف Scroll-Driven Animations
المتصفحات الحديثة تدعم scroll-driven animations — طريقة CSS خالصة للتحريك بناءً على موضع التمرير، بدون JavaScript. المثال أدناه يقلّص لون خلفية الرأس تدريجياً مع تمرير المستخدم، باستخدام
animation-timeline: scroll(). دعم المتصفحات: Chromium 115+ وFirefox 110+ — استخدمه كتحسين تدريجي.css@supports (animation-timeline: scroll()) { .site-header { animation: shrink-header linear both; animation-timeline: scroll(); animation-range: 0px 80px; } @keyframes shrink-header { from { padding-block: 1.25rem; background: transparent; } to { padding-block: 0.5rem; background: #fff; box-shadow: 0 1px 8px rgb(0 0 0 / .08); } } } -
7
إمكانية الوصول — إبقاء التركيز في مكانه
حين يختفي الرأس، تظل العناصر التفاعلية بداخله (روابط التنقل، زر البحث) مخفية لكن تبقى في ترتيب التبويب. أضف
inertللرأس حين يكون مخفياً، وأزله حين يعود للظهور. هذا يُزيله من تركيز التبويب وإعلانات قارئ الشاشة دون إزالته من DOM.javascriptwindow.addEventListener('scroll', () => { const currentScrollY = window.scrollY; if (currentScrollY < THRESHOLD) { header.classList.remove('is-hidden'); header.removeAttribute('inert'); lastScrollY = currentScrollY; return; } const scrollingDown = currentScrollY > lastScrollY; header.classList.toggle('is-hidden', scrollingDown); header.toggleAttribute('inert', scrollingDown); lastScrollY = currentScrollY; }, { passive: true });
نصائح ومحاذير
- اجعل مستمع التمرير دائماً <code>{ passive: true }</code> — هذا يُخبر المتصفح أن المعالج لن يستدعي <code>preventDefault()</code> أبداً، مما يُتيح تحسينات أداء التمرير.
- إذا كانت صفحتك تحتوي روابط مرساة، فإن الرأس الثابت المخفي سيتداخل مع الهدف. عوّض ذلك بـ <code>scroll-margin-top</code> على العناصر المرتبطة: <code>:target { scroll-margin-top: 80px; }</code>.
- للقوائم المفتوحة داخل الرأس (القوائم المنسدلة، التنقل على الجوال)، أوقف مؤقتاً منطق الإخفاء عند التمرير لأسفل أثناء فتح القائمة — وإلا قد يختفي الرأس في منتصف التفاعل.
- <code>position: sticky</code> يتطلب ألّا يملك الأب <code>overflow: hidden</code> أو <code>overflow: auto</code> — هذا يقطع خاصية الالتصاق.
خاتمة
رأس الصفحة الثابت المبني جيداً هو عقد من جزأين: CSS يتولى الحركة (سلسة، معتمدة على GPU)، وJavaScript يتولى قرار الحالة فقط (إخفاء أم إظهار). ابقِ معالج التمرير خفيفاً وسلبياً، أضف الحد لتجنّب الوميض قرب الأعلى، وتعامل مع السمة inert للحفاظ على إمكانية الوصول. ستُحل الـ scroll-driven animations API محل نهج JavaScript بالكامل في نهاية المطاف — ابدأ بنمط CSS-first الآن.