→ לכל המאגר

B41 · סקשן מוצמד שהתוכן בו מתחלף בגלילה

התנהגויות GSAP · ScrollTrigger תהליך ושלביםתמונות וגלריותכרטיסים ממתין

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

מתי משתמשים: פיצ'רים, שירותים, שלבי עבודה, יתרונות. הדפוס הזה חזר שש פעמים באוסף הקלונאבלס של Webflow ועוד פעם ב-21st.dev, והוא מחליף ארבעה סקשנים בסקשן אחד.

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

הדמו

גלול למטה, הדמו מגיע ↓
1
2
3
4
01

אפיון לפני עיצוב

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

1
02

קופי שמדבר אל הלקוח

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

2
03

עיצוב בשפה אחת

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

3
04

מדידה מהיום הראשון

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

4
עוד מסלול גלילה. נסה גם חזרה למעלה ↑
הקסם הוא שילוב של שניים: הפאנל נפתח ב-grid-template-rows מ-0fr ל-1fr כדי לקבל גובה אמיתי, והמדיה נשארת במקום עם position:sticky. בגרסת המובייל אין מקום לעמודה דביקה, ולכן התמונה עוברת לתוך הפריט הפתוח עצמו. אין pin ואין חישובי גובה, ולכן זה לא נשבר כשהטקסט מתארך.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --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}
.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)}
.ph-l{background:rgba(16,18,43,.72);color:#fff;padding:.18em .7em;border-radius:999px;line-height:1.3;font-size:max(.78em,12px)}

/* B41 · סקשן מוצמד שהתוכן בו מתחלף בגלילה */
.ss{position:relative}
.ss-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,4vw,70px);align-items:start;
  padding-inline:var(--gutter, clamp(24px, 5vw, 96px));max-width:1180px;margin-inline:auto}
.ss-media{position:sticky;top:16vh;aspect-ratio:4/3;border-radius:var(--r, 14px);overflow:hidden}
.ss-media .ph{position:absolute;inset:0;border-radius:0;font-size:38px;opacity:0;transform:scale(1.05);
  transition:opacity .55s ease,transform .9s cubic-bezier(.2,.6,.2,1)}
.ss-media .ph.on{opacity:1;transform:none}
.ss-list{display:grid}
.ss-item{border-top:1px solid var(--line, #e4e4ee);padding-block:clamp(16px,2vw,26px)}
.ss-item:last-child{border-bottom:1px solid var(--line, #e4e4ee)}
.ss-head{display:flex;align-items:center;gap:14px}
.ss-idx{font-size:13px;color:var(--muted, #6a6d85);font-variant-numeric:tabular-nums}
.ss-item h3{margin:0;font-size:clamp(19px,2.1vw,30px);color:var(--muted, #6a6d85);transition:color .35s}
.ss-item.on h3{color:var(--ink, #16182b)}
.ss-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .5s cubic-bezier(.2,.6,.2,1)}
.ss-item.on .ss-body{grid-template-rows:1fr}
.ss-body>div{overflow:hidden}
.ss-body p{margin:12px 0 0;color:var(--muted, #6a6d85);font-size:16px;line-height:1.7;max-width:46ch}
.ss-mobile{display:none}
@media(max-width:860px){
  .ss-grid{grid-template-columns:1fr}
  .ss-media{display:none}
  .ss-mobile{display:block;aspect-ratio:16/10;border-radius:var(--r, 14px);overflow:hidden;margin-top:14px;position:relative}
  .ss-mobile .ph{position:absolute;inset:0;border-radius:0;font-size:26px}
}
@media (prefers-reduced-motion: reduce){.ss-body,.ss-media .ph{transition-duration:.01ms}}

HTML

<div class="stage"><div class="ss"><div class="ss-grid">
  <div class="ss-media">
    <div class="ph ph-a on"><span class="ph-l">1</span></div><div class="ph ph-c"><span class="ph-l">2</span></div><div class="ph ph-d"><span class="ph-l">3</span></div><div class="ph ph-e"><span class="ph-l">4</span></div>
  </div>
  <div class="ss-list">
    <div class="ss-item on" data-i="0"><div class="ss-head"><span class="ss-idx">01</span><h3>אפיון לפני עיצוב</h3></div>
      <div class="ss-body"><div><p>מתחילים בהבנה של העסק ושל הלקוח, ורק אחר כך פותחים כלי עיצוב. זה השלב שקובע אם האתר יביא פניות.</p>
      <div class="ss-mobile"><div class="ph ph-a"><span class="ph-l">1</span></div></div></div></div></div>
    <div class="ss-item" data-i="1"><div class="ss-head"><span class="ss-idx">02</span><h3>קופי שמדבר אל הלקוח</h3></div>
      <div class="ss-body"><div><p>כל כותרת עונה על שאלה אמיתית שיש למי שנחת בעמוד, במקום לתאר את העסק מבפנים.</p>
      <div class="ss-mobile"><div class="ph ph-c"><span class="ph-l">2</span></div></div></div></div></div>
    <div class="ss-item" data-i="2"><div class="ss-head"><span class="ss-idx">03</span><h3>עיצוב בשפה אחת</h3></div>
      <div class="ss-body"><div><p>מערכת אחת של צבעים, טיפוגרפיה וריווח שחוזרת בכל עמוד, כך שהאתר מרגיש שלם ולא אוסף מסכים.</p>
      <div class="ss-mobile"><div class="ph ph-d"><span class="ph-l">3</span></div></div></div></div></div>
    <div class="ss-item" data-i="3"><div class="ss-head"><span class="ss-idx">04</span><h3>מדידה מהיום הראשון</h3></div>
      <div class="ss-body"><div><p>מחברים מעקב לפני העלייה לאוויר, כדי שנדע מה עובד במקום לנחש חודש אחרי.</p>
      <div class="ss-mobile"><div class="ph ph-e"><span class="ph-l">4</span></div></div></div></div></div>
  </div>
</div></div></div>

JS

gsap.registerPlugin(ScrollTrigger);

(function(){
  const items=gsap.utils.toArray(".ss-item");
  const shots=[...document.querySelectorAll(".ss-media .ph")];
  function activate(i){
    items.forEach((it,n)=>it.classList.toggle("on",n===i));
    shots.forEach((s,n)=>s.classList.toggle("on",n===i));
  }
  items.forEach((item,i)=>{
    ScrollTrigger.create({trigger:item,start:"top 62%",end:"bottom 45%",
      onToggle:self=>{if(self.isActive)activate(i);}});
  });
})();