→ לכל המאגר

B38 · הדר שמתחבא בגלילה וחוזר

התנהגויות JS · CSS transform ניווט ומבנה ממתין

בגלילה למטה ההדר מחליק החוצה ומפנה מסך, ובגלילה קלה למעלה הוא חוזר מיד. בראש העמוד הוא שקוף ומתמלא ברקע ברגע שיוצאים מהירו. כאן הוא רץ בתוך מסגרת גלילה עצמאית, כדי שאפשר יהיה לשפוט אותו בלי ההדר של המאגר מעליו.

מתי משתמשים: כל אתר. זו התנהגות ההדר הנפוצה ביותר, והיא פותרת את הקונפליקט בין ניווט תמיד זמין לבין מסך נקי לתוכן.

הדמו כאן עיצובי-ניטרלי בכוונה. כשהמהלך נכנס לפרויקט, מיובאת רק ההתנהגות: הצבעים, הרדיוסים, הפונטים והצללים יורשים את העיצוב של אותו פרויקט.

הדמו

לוגו

גלול למטה וההדר ייעלם

גלול קצת חזרה למעלה והוא יחזור מיד

ההתנהגות הזאת פותרת בעיה אמיתית: הדר קבוע גוזל גובה יקר במובייל, אבל הדר שנעלם לגמרי מכריח את הגולש לחזור עד למעלה. הפשרה היא הדר שמגיב לכוונה: יורדים, הוא מתפנה; רוצים לנווט, מרימים קצת והוא כבר שם.

שני פרטים שקובעים אם זה מרגיש טוב: סף מרחק שמונע ריצוד בגלילות זעירות, וכניסה מיידית לרקע אטום ברגע שעוזבים את הירו, כדי שהטקסט מאחור לא יתערבב בניווט.

גלול עוד קצת בתוך המסגרת. אחר כך גלול למעלה בעדינות.

עוד תוכן, כדי שיהיה מסלול גלילה אמיתי לבדיקה.

סוף העמוד.

גלול בתוך המסגרת, לא בעמוד.

הסף של 90 פיקסלים הוא הפרט החשוב: בלעדיו ההדר מרצד בכל תזוזה קטנה של הטראקפד. הצבירה מתאפסת בכל שינוי כיוון, ולכן גלילה קצרה למעלה מחזירה אותו מיד. מתחת ל-80 פיקסלים מהראש הוא תמיד גלוי, כדי שלא ייתקע מוסתר בראש העמוד. **הערת דמו**: כאן ההדר הוא `position:sticky` בתוך מסגרת שגוללת בעצמה, כי לעמוד המאגר כבר יש הדר משלו ואי אפשר היה לשפוט את המהלך. בפרויקט אמיתי מחליפים לשורה אחת: `position:fixed` עם `inset-inline:0`, ומאזינים ל-window במקום למסגרת.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --accent או --line משלו יורש אותם אוטומטית. הרכיב הזה מסתמך על dir="rtl".

פתח קובץ עצמאי ↗
הצג את הקוד כאן

CSS

/* מחלקות עזר של המאגר שהרכיב הזה משתמש בהן */
.stage{padding:var(--sec, clamp(120px, 12vw, 260px)) var(--gutter, clamp(24px, 5vw, 96px));position:relative}
.stage.tight{padding-block:clamp(48px,5vw,90px)}
.stage.full{padding-inline:0}

/* B38 · הדר שמתחבא בגלילה וחוזר */
.hd-frame{position:relative;height:clamp(420px,76vh,640px);overflow-y:auto;overscroll-behavior:contain;
  border:1px solid var(--line, #e4e4ee);border-radius:var(--r, 14px);margin-inline:var(--gutter, clamp(24px, 5vw, 96px));background:var(--bg, #f7f7fa)}
.hd-frame::-webkit-scrollbar{width:8px}
.hd-frame::-webkit-scrollbar-thumb{background:#c9cbdb;border-radius:99px}
.hd-hint{text-align:center;color:var(--muted, #6a6d85);font-size:14px;margin:14px 0 0}
/* sticky ולא fixed, כי כאן ההקשר הוא המסגרת. באתר אמיתי זה position:fixed על החלון. */
.hd-bar{position:sticky;top:0;z-index:50;display:flex;align-items:center;justify-content:space-between;
  padding:16px clamp(16px,3vw,30px);
  transition:/* qa-allow: layout, ההתכווצות של ההדר היא הפיצ'ר */transform .42s cubic-bezier(.2,.6,.2,1),background-color .35s,padding .35s,box-shadow .35s;
  background:transparent}
.hd-bar.solid{background:rgba(247,247,250,.9);backdrop-filter:blur(12px);box-shadow:0 1px 0 var(--line, #e4e4ee);padding-block:11px}
.hd-bar.up{transform:translateY(-105%)}
.hd-bar nav{display:flex;gap:6px;flex-wrap:wrap}
.hd-bar nav a{color:var(--ink, #16182b);text-decoration:none;font-size:15px;padding:8px 14px;border-radius:999px;transition:background .25s}
.hd-bar nav a:hover{background:#eceaff}
.hd-cta{background:var(--ink, #16182b);color:var(--bg, #f7f7fa)!important;font-weight:600}
.hd-hero{min-height:100%;margin-top:-72px;display:grid;place-items:center;text-align:center;padding:90px clamp(16px,3vw,30px) 40px;
  background:linear-gradient(160deg,#eceaff,var(--bg, #f7f7fa))}
.hd-hero h2{font-size:clamp(26px,3.6vw,52px);margin:0 0 10px;font-weight:800}
.hd-hero p{margin:0;color:var(--muted, #6a6d85)}
.hd-body{padding:clamp(30px,5vw,70px) clamp(16px,3vw,30px);max-width:62ch;margin-inline:auto;color:var(--muted, #6a6d85)}
.hd-body p{margin:0 0 18px;line-height:1.8}
@media (prefers-reduced-motion: reduce){.hd-bar{transition:background-color .3s}.hd-bar.up{transform:none}}

HTML

<div class="stage tight">
<div class="hd-frame">
  <header class="hd-bar">
    <strong>לוגו</strong>
    <nav><a href="#">עבודות</a><a href="#">שירותים</a><a class="hd-cta" href="#">דברו איתנו</a></nav>
  </header>
  <section class="hd-hero"><div><h2>גלול למטה וההדר ייעלם</h2><p>גלול קצת חזרה למעלה והוא יחזור מיד</p></div></section>
  <div class="hd-body">
    <p>ההתנהגות הזאת פותרת בעיה אמיתית: הדר קבוע גוזל גובה יקר במובייל, אבל הדר שנעלם לגמרי מכריח את הגולש לחזור עד למעלה. הפשרה היא הדר שמגיב לכוונה: יורדים, הוא מתפנה; רוצים לנווט, מרימים קצת והוא כבר שם.</p>
    <p>שני פרטים שקובעים אם זה מרגיש טוב: סף מרחק שמונע ריצוד בגלילות זעירות, וכניסה מיידית לרקע אטום ברגע שעוזבים את הירו, כדי שהטקסט מאחור לא יתערבב בניווט.</p>
    <p>גלול עוד קצת בתוך המסגרת. אחר כך גלול למעלה בעדינות.</p>
    <p style="height:70vh"></p>
    <p>עוד תוכן, כדי שיהיה מסלול גלילה אמיתי לבדיקה.</p>
    <p style="height:70vh"></p>
    <p>סוף העמוד.</p>
  </div>
</div>
<p class="hd-hint">גלול בתוך המסגרת, לא בעמוד.</p>
</div>

JS

(function(){
  const frame=document.querySelector(".hd-frame");
  const bar=frame.querySelector(".hd-bar");
  const hero=frame.querySelector(".hd-hero");
  let last=frame.scrollTop,acc=0;
  const THRESH=90;   // כמה צריך לגלול ברצף לפני שההדר מגיב. מונע ריצוד.
  function onScroll(){
    const y=frame.scrollTop;
    const d=y-last;last=y;
    bar.classList.toggle("solid",y>hero.offsetHeight*0.6);
    if(y<80){bar.classList.remove("up");acc=0;return;}
    // צוברים מרחק באותו כיוון, ומאפסים כשמתהפכים
    if((d>0&&acc<0)||(d<0&&acc>0))acc=0;
    acc+=d;
    if(acc>THRESH){bar.classList.add("up");acc=0;}
    if(acc<-THRESH){bar.classList.remove("up");acc=0;}
  }
  frame.addEventListener("scroll",onScroll,{passive:true});
  onScroll();
})();