ציר זמן שבו השנה יושבת דבוקה בצד, ואירועים גוללים לצידה. כשעוברים לשנה הבאה הספרות מתגלגלות למעלה כמו מונה, והקו מתמלא.
מתי משתמשים: היסטוריה של חברה, אבני דרך, סיפור מסע. ארבע עד שמונה שנים.
הדמו כאן עיצובי-ניטרלי בכוונה. כשהמהלך נכנס לפרויקט, מיובאת רק ההתנהגות: הצבעים, הרדיוסים, הפונטים והצללים יורשים את העיצוב של אותו פרויקט.
גלול לאורך השנים
שולחן אחד, לקוח אחד, ואתר ראשון שעלה לאוויר.
שלושה אנשים, עשרות פרויקטים בשנה.
ה-CRM הראשון שבנינו ללקוח עדיין רץ.
אתר, מערכת ואוטומציה תחת קורת גג אחת.
הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --accent או --line משלו יורש אותם אוטומטית. הרכיב הזה מסתמך על dir="rtl".
/* G107 · שנה דביקה שמתחלפת בציר זמן */
.yr{display:grid;grid-template-columns:auto 1fr;gap:clamp(24px,5vw,80px);max-width:min(900px,92vw);margin-inline:auto;padding-block:10vh 30vh;position:relative}
.yr-side{position:sticky;top:0;height:100vh;display:grid;align-content:center;gap:18px}
.yr-num{display:flex;direction:ltr;font-size:clamp(48px,7vw,110px);font-weight:900;line-height:1;font-variant-numeric:tabular-nums;color:var(--ink, #16182b)}
.yr-d{position:relative;height:1em;width:.62em;overflow:hidden}
.yr-d span{position:absolute;inset:0;text-align:center}
.yr-line{position:absolute;inset-block:0;inset-inline-start:calc(clamp(48px,7vw,110px) * 2.6 + clamp(24px,5vw,80px) / 2);width:2px;background:var(--line, #e4e4ee)}
.yr-fill{position:absolute;inset:0;background:var(--accent, #4a3aff);transform-origin:50% 0;transform:scaleY(0)}
.yr-list{display:grid;gap:30vh;padding-block:30vh}
.yr-ev h3{margin:0 0 8px;font-size:clamp(20px,2.4vw,32px)}
.yr-ev p{margin:0;color:var(--muted, #6a6d85);line-height:1.7;max-width:40ch}
@media(max-width:767px){.yr{grid-template-columns:1fr}.yr-side{height:auto;top:0;padding:14px 0;background:var(--bg, #f7f7fa);z-index:2}.yr-line{display:none}.yr-list{gap:20vh;padding-block:6vh 20vh}}
<div class="yr">
<div class="yr-side"><div class="yr-num" aria-live="polite"></div><p style="margin:0;color:var(--muted)">גלול לאורך השנים</p></div>
<div class="yr-line" aria-hidden="true"><div class="yr-fill"></div></div>
<div class="yr-list">
<div class="yr-ev" data-year="2016"><h3>מתחילים מהבית</h3><p>שולחן אחד, לקוח אחד, ואתר ראשון שעלה לאוויר.</p></div>
<div class="yr-ev" data-year="2019"><h3>עוברים לסטודיו</h3><p>שלושה אנשים, עשרות פרויקטים בשנה.</p></div>
<div class="yr-ev" data-year="2022"><h3>מערכות, לא רק אתרים</h3><p>ה-CRM הראשון שבנינו ללקוח עדיין רץ.</p></div>
<div class="yr-ev" data-year="2026"><h3>היום</h3><p>אתר, מערכת ואוטומציה תחת קורת גג אחת.</p></div>
</div>
</div>
gsap.registerPlugin(ScrollTrigger);
(function(){
const num=document.querySelector(".yr-num"),evs=gsap.utils.toArray(".yr-ev"),reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
const digits=[];for(let i=0;i<4;i++){const d=document.createElement("div");d.className="yr-d";const a=document.createElement("span"),b=document.createElement("span");d.append(a,b);num.appendChild(d);digits.push({a,b,cur:""});}
function set(year){[...year].forEach((ch,i)=>{const d=digits[i];if(d.cur===ch)return;
if(d.cur===""||reduce){d.a.textContent=ch;gsap.set(d.a,{yPercent:0});gsap.set(d.b,{yPercent:100});d.cur=ch;return;}
const dir=+ch>+d.cur?1:-1;d.b.textContent=ch;
gsap.fromTo(d.b,{yPercent:100*dir},{yPercent:0,duration:.5,ease:"power3.inOut"});
gsap.to(d.a,{yPercent:-100*dir,duration:.5,ease:"power3.inOut",onComplete(){d.a.textContent=ch;gsap.set(d.a,{yPercent:0});gsap.set(d.b,{yPercent:100});}});
d.cur=ch;});}
set(evs[0].dataset.year);
evs.forEach(e=>ScrollTrigger.create({trigger:e,start:"top 60%",end:"bottom 40%",onEnter:()=>set(e.dataset.year),onEnterBack:()=>set(e.dataset.year)}));
gsap.to(".yr-fill",{scaleY:1,ease:"none",scrollTrigger:{trigger:".yr-list",start:"top 60%",end:"bottom 60%",scrub:reduce?false:.3}});
})();