→ לכל המאגר

G67 · קלפים שנפרשים כמניפה בגלילה

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

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

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

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

הדמו

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

גלול. הערימה נפרשת ונאספת.

`transform-origin` מתחת לקלף הוא כל הסוד: סיבוב סביב נקודה שנמצאת מתחת לקלף מייצר מניפה, וסיבוב סביב המרכז מייצר ערימה מבולגנת. הזווית והמרחק נגזרים מהמרחק מהקלף האמצעי, ולכן אפשר להוסיף קלף שישי בלי לגעת במספרים. ה-`yPercent` הקטן שגדל עם המרחק מהאמצע הוא מה שמייצר את הקשת: בלעדיו הקלפים נפרשים על קו ישר ונראים כמו כרטיסים שהודבקו. `zIndex` נגזר גם הוא מהמרחק מהאמצע, כך שהקלף המרכזי תמיד מעל.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --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-b{background:linear-gradient(160deg,#5f3dc4,#9775fa)}
.ph-c{background:linear-gradient(160deg,#0b7285,#3bc9db)}
.ph-d{background:linear-gradient(160deg,#2b8a3e,#69db7c)}
.ph-e{background:linear-gradient(160deg,#e8590c,#ffa94d)}

/* G67 · קלפים שנפרשים כמניפה בגלילה */
.fn{height:260vh;position:relative}
.fn-stage{position:sticky;top:0;height:100vh;display:grid;place-items:center;overflow:hidden}
.fn-deck{position:relative;width:min(1000px,92vw);height:min(58vh,460px)}
.fn-card{position:absolute;top:0;left:50%;width:clamp(150px,19vw,240px);height:100%;
  margin-inline-start:calc(clamp(150px,19vw,240px) / -2);
  border-radius:18px;overflow:hidden;background:var(--card, #fff);border:1px solid var(--line, #e4e4ee);
  box-shadow:0 20px 50px rgba(20,20,40,.16);transform-origin:50% 130%;will-change:transform}
.fn-card .ph{aspect-ratio:1;border-radius:0;font-size:0}
.fn-card b{display:block;padding:12px 14px 4px;font-size:15px}
.fn-card span{display:block;padding:0 14px 14px;font-size:13px;color:var(--muted, #6a6d85);line-height:1.55}
.fn-cap{position:absolute;bottom:7vh;inset-inline:0;text-align:center;color:var(--muted, #6a6d85);font-size:15px}

HTML

<div class="fn"><div class="fn-stage">
  <div class="fn-deck">
    <article class="fn-card"><div class="ph ph-a"></div><b>אפיון</b><span>מבינים לפני שמעצבים</span></article>
    <article class="fn-card"><div class="ph ph-c"></div><b>קופי</b><span>המסר קובע את המבנה</span></article>
    <article class="fn-card"><div class="ph ph-d"></div><b>עיצוב</b><span>שפה אחת בכל עמוד</span></article>
    <article class="fn-card"><div class="ph ph-e"></div><b>פיתוח</b><span>מהיר ונכון בכל מסך</span></article>
    <article class="fn-card"><div class="ph ph-b"></div><b>מדידה</b><span>יודעים מה עובד</span></article>
  </div>
  <p class="fn-cap">גלול. הערימה נפרשת ונאספת.</p>
</div></div>

JS

gsap.registerPlugin(ScrollTrigger);

(function(){
  const cards=gsap.utils.toArray(".fn-card");
  const n=cards.length, mid=(n-1)/2;
  const reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
  if(reduce){cards.forEach((c,i)=>gsap.set(c,{rotation:(i-mid)*11,xPercent:(i-mid)*86,yPercent:Math.abs(i-mid)*7}));return;}
  const tl=gsap.timeline({scrollTrigger:{trigger:".fn",start:"top top",end:"bottom bottom",scrub:.6}});
  cards.forEach((c,i)=>{
    const off=i-mid;
    // הזווית ומרחק הפריסה נגזרים מהמרחק מהאמצע, ולכן זה נשאר סימטרי בכל מספר קלפים
    tl.fromTo(c,{rotation:0,xPercent:0,yPercent:0,zIndex:n-Math.abs(off)},
      {rotation:off*11,xPercent:off*86,yPercent:Math.abs(off)*7,ease:"power2.out"},0);
  });
})();