→ לכל המאגר

G50 · וילון מעבר בין עמודים

GSAP GSAP · timeline ניווט ומבנהטעינה ופידבקרקע ואווירה ממתין

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

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

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

הדמו

אתרי תדמית

לחץ על אחד הקישורים. הוילון עולה, התוכן מתחלף מאחוריו, והוילון יורד.

באתר רב-עמודי אמיתי מחליפים את שורת החלפת התוכן ב-`location.href=a.href`, ובטעינת העמוד החדש מריצים רק את `reveal()` כשהוילון מתחיל במצב מכסה. שתי מלכודות: צריך לדלג על קישורים חיצוניים, על עוגנים ועל לחיצה עם Ctrl או עם גלגל, אחרת שוברים פתיחה בלשונית חדשה; ובחזרה עם כפתור אחורה הדפדפן מחזיר את העמוד מהמטמון בלי טעינה, ולכן חייבים להאזין ל-`pageshow` ולהריץ שם `reveal()` גם כן, אחרת הוילון נשאר תקוע על המסך. ההשהיה בין הרצועות היא מה שמייצר את התחושה; וילון אחד שעולה במלואו נראה כמו מסך שנדלק.

קוד להדבקה

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

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

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}

/* G50 · וילון מעבר בין עמודים */
.pt-page{min-height:64vh;display:grid;place-items:center;text-align:center;padding:8vh var(--gutter, clamp(24px, 5vw, 96px))}
.pt-page h3{font-size:clamp(28px,5vw,62px);margin:0 0 12px}
.pt-page p{color:var(--muted, #6a6d85);font-size:17px;line-height:1.8;max-width:44ch;margin:0 auto 24px}
.pt-nav{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
.pt-nav a{padding:11px 20px;border-radius:999px;border:1px solid var(--line, #e4e4ee);background:var(--card, #fff);
  color:var(--ink, #16182b);text-decoration:none;font-size:15px}
.pt-nav a.on{background:var(--ink, #16182b);border-color:var(--ink, #16182b);color:var(--bg, #f7f7fa)}
/* הוילון: ארבע רצועות שעולות בהפרש קטן, כך שהכיסוי מרגיש כמו תנועה ולא כמו מסך שנדלק */
.pt-curtain{position:fixed;inset:0;z-index:90;pointer-events:none;display:grid;grid-template-columns:repeat(4,1fr)}
.pt-curtain i{background:var(--ink, #16182b);transform:translateY(101%)}
.pt-label{position:fixed;inset:0;z-index:91;display:grid;place-items:center;color:#fff;font-size:clamp(22px,4vw,44px);
  font-weight:800;opacity:0;pointer-events:none}

HTML

<div class="stage tight"><div class="pt-page" id="pt-view">
  <div>
    <h3>אתרי תדמית</h3>
    <p>לחץ על אחד הקישורים. הוילון עולה, התוכן מתחלף מאחוריו, והוילון יורד.</p>
    <nav class="pt-nav">
      <a href="#" data-t="אתרי תדמית" class="on">אתרי תדמית</a>
      <a href="#" data-t="דפי נחיתה">דפי נחיתה</a>
      <a href="#" data-t="חנויות">חנויות</a>
      <a href="#" data-t="צור קשר">צור קשר</a>
    </nav>
  </div>
</div></div>
<div class="pt-curtain"><i></i><i></i><i></i><i></i></div>
<div class="pt-label"></div>

JS

(function(){
  const bars=gsap.utils.toArray(".pt-curtain i"),label=document.querySelector(".pt-label");
  const view=document.querySelector("#pt-view");
  const reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
  const D=reduce?0:.5;
  function cover(text){
    label.textContent=text;                      // קודם הטקסט, אחר כך החשיפה. אחרת רואים לרגע את השם הקודם
    return gsap.timeline()
      .to(bars,{yPercent:-101,duration:D,ease:"power3.inOut",stagger:.05})
      .to(label,{opacity:1,duration:D*.5},"-="+D*.5);
  }
  function reveal(){
    return gsap.timeline()
      .to(label,{opacity:0,duration:D*.4})
      .to(bars,{yPercent:-202,duration:D,ease:"power3.inOut",stagger:.05},"-="+D*.2)
      .set(bars,{yPercent:101});     // מחזירים למטה בלי אנימציה, מוכנים למעבר הבא
  }
  document.querySelectorAll(".pt-nav a").forEach(a=>{
    a.addEventListener("click",e=>{
      e.preventDefault();
      if(a.classList.contains("on"))return;
      document.querySelectorAll(".pt-nav a").forEach(x=>x.classList.toggle("on",x===a));
      gsap.timeline()
        .add(cover(a.dataset.t))
        // כאן, מתחת לוילון, מחליפים תוכן. באתר אמיתי: location.href=a.href
        .add(()=>{view.querySelector("h3").textContent=a.dataset.t;scrollTo(0,0);})
        .add(reveal());
    });
  });
  gsap.set(bars,{yPercent:101});
})();