→ לכל המאגר

G59 · כרטיסים שמתקרבים מהעומק בגלילה

GSAP GSAP · ScrollTrigger · perspective כרטיסיםתהליך ושלביםהירו ופתיחה ממתין

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

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

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

הדמו

גלול. הכרטיסים מגיעים מרחוק וחולפים.

שיחת אפיון

מבינים את העסק, את הלקוח ואת מה שצריך לקרות באתר, לפני שנוגעים בעיצוב.

קופי ומבנה

כותבים את המסרים ובונים את סדר הסקשנים, כך שכל גלילה עונה על השאלה הבאה.

עיצוב ופיתוח

הופכים את המבנה לאתר חי, מהיר, שנראה נכון בכל מסך.

עלייה ומדידה

מחברים מעקב, עולים לאוויר, ובודקים מה עובד במקום לנחש.

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

שלוש הכרעות. הראשונה: `perspective` יושב על המעטפת ולא על הכרטיס, אחרת לכל כרטיס יש נקודת מגוז משלו והעומק נשבר. השנייה: הטשטוש הוא מה שקונה את האשליה. תנועה ב-`z` בלבד נקראת כהגדלה, וברגע שהרחוק מטושטש המוח מפרש מרחק. `filter:blur` יקר, ולכן הוא נשאר על ארבעה כרטיסים ולא על עשרים. השלישית: `immediateRender` פעיל רק לכרטיס הראשון; בלעדיו כל ארבעת ה-fromTo מציירים את מצב ההתחלה שלהם בבנייה, והכרטיס הראשון נדחף אחורה לפני שהגלילה בכלל התחילה. החפיפה בין הפרקים היא מה שמונע רגע ריק בין כרטיס לכרטיס.

קוד להדבקה

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

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

CSS

/* מחלקות עזר של המאגר שהרכיב הזה משתמש בהן */
.ph{display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;border-radius:var(--r, 14px)}
.ph-a{background:linear-gradient(160deg,#3b5bdb,#748ffc)}
.ph-c{background:linear-gradient(160deg,#0b7285,#3bc9db)}
.ph-d{background:linear-gradient(160deg,#2b8a3e,#69db7c)}
.ph-e{background:linear-gradient(160deg,#e8590c,#ffa94d)}

/* G59 · כרטיסים שמתקרבים מהעומק בגלילה */
.dp{height:340vh;position:relative}
.dp-stick{position:sticky;top:0;height:100vh;overflow:hidden;display:grid;place-items:center;
  perspective:900px;perspective-origin:50% 50%}
.dp-card{position:absolute;width:min(420px,84vw);border-radius:20px;background:var(--card, #fff);
  border:1px solid var(--line, #e4e4ee);padding:clamp(20px,2.6vw,34px);box-shadow:0 24px 60px rgba(20,20,40,.14);
  will-change:transform,opacity,filter}
.dp-card .ph{aspect-ratio:16/9;border-radius:12px;font-size:0;margin-bottom:16px}
.dp-card h4{margin:0 0 8px;font-size:clamp(19px,2vw,26px)}
.dp-card p{margin:0;color:var(--muted, #6a6d85);font-size:15.5px;line-height:1.7}
.dp-num{position:absolute;top:8vh;inset-inline:0;text-align:center;color:var(--muted, #6a6d85);font-size:14px;z-index:3}
.dp-after{padding:14vh var(--gutter, clamp(24px, 5vw, 96px));max-width:min(680px,92vw);margin-inline:auto;text-align:center;
  color:var(--muted, #6a6d85);font-size:17px;line-height:1.9}

HTML

<div class="dp"><div class="dp-stick">
  <p class="dp-num">גלול. הכרטיסים מגיעים מרחוק וחולפים.</p>
  <article class="dp-card"><div class="ph ph-a"></div><h4>שיחת אפיון</h4>
    <p>מבינים את העסק, את הלקוח ואת מה שצריך לקרות באתר, לפני שנוגעים בעיצוב.</p></article>
  <article class="dp-card"><div class="ph ph-c"></div><h4>קופי ומבנה</h4>
    <p>כותבים את המסרים ובונים את סדר הסקשנים, כך שכל גלילה עונה על השאלה הבאה.</p></article>
  <article class="dp-card"><div class="ph ph-d"></div><h4>עיצוב ופיתוח</h4>
    <p>הופכים את המבנה לאתר חי, מהיר, שנראה נכון בכל מסך.</p></article>
  <article class="dp-card"><div class="ph ph-e"></div><h4>עלייה ומדידה</h4>
    <p>מחברים מעקב, עולים לאוויר, ובודקים מה עובד במקום לנחש.</p></article>
</div></div>
<p class="dp-after">הטשטוש הוא מה שהופך את זה לעומק ולא להגדלה. בלעדיו הכרטיס פשוט גדל, ועם קצת ממנו העין מפרשת מרחק.</p>

JS

gsap.registerPlugin(ScrollTrigger);

(function(){
  const cards=gsap.utils.toArray(".dp-card");
  const reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
  if(reduce){gsap.set(cards,{position:"relative",opacity:1,marginBottom:24});return;}
  const FAR=-1400, NEAR=460, SLOT=.6, DUR=.9;
  const tl=gsap.timeline({scrollTrigger:{trigger:".dp",start:"top top",end:"bottom bottom",scrub:.6}});
  cards.forEach((c,i)=>{
    // כל כרטיס תופס פרק זמן משלו, והפרקים חופפים כדי שתמיד יהיה משהו על המסך.
    // כל ה-fromTo מציירים את מצב ההתחלה מיד, ולכן כולם מתחילים רחוק ושקופים.
    tl.fromTo(c,{z:FAR,opacity:0,filter:"blur(14px)"},
      {z:NEAR,opacity:1,filter:"blur(0px)",ease:"none",duration:DUR},i*SLOT)
      // האטימות עולה מהר יותר מהמרחק, אחרת יש רגע שבו הכרטיס הבא עוד שקוף והקודם כבר יצא
      .to(c,{opacity:1,duration:DUR*.4,ease:"none"},i*SLOT);
    // האחרון נשאר, כדי שסוף הסקשן לא יהיה מסך ריק
    if(i<cards.length-1)tl.to(c,{opacity:0,ease:"none",duration:.25},i*SLOT+DUR*.86);
  });
})();