→ לכל המאגר

G70 · כותרת שמתכווצת ומתעגנת לפינה

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

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

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

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

הדמו

אפיון

מה קורה בשלב הזה

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

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

מה יוצא מזה

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

גלול והכותרת למעלה תתכווץ לתווית. גלול חזרה והיא תחזור להיות כותרת מלאה.

אין כאן שום מדידה בזמן ריצה: שני המצבים מוגדרים במלואם, ו-GSAP עושה אינטרפולציה בין אחוזים לפיקסלים. המרכוז מושג בשילוב `right:50%` עם `xPercent:50`, כלומר הקצה הימני במרכז ואז דחיפה של חצי רוחב. **הניסיון הראשון כאן נכשל**: מדדתי בזמן ריצה את המרחק אל המרכז, אבל המדידה נעשית על אלמנט שכבר נושא טרנספורם, ולכן היא מזינה את עצמה והכותרת ברחה מהמסך. העיגון עובד כי `transform-origin` נמצא בקצה שאליו הכותרת נוסעת: בעברית זה `100% 0%`, כלומר הפינה הימנית העליונה, ולכן ההתכווצות מושכת אותה ימינה במקום להשאיר אותה תלויה באוויר. הכותרת יושבת בשכבה `sticky` נפרדת עם `pointer-events:none`, והתוכן נמשך מעליה ב-`margin-top:-100vh`, כך שהיא מרחפת מעל הטקסט בלי לחסום לחיצות. הטווח מוגדר כ-`+=70%` של גובה המסך ולא כאחוז מגובה הפרק. **זו הייתה תקלה אמיתית כאן**: טווח שנגזר מגובה הפרק יצא ארוך יותר ממה שאפשר לגלול בפועל, ולכן שליש מהאנימציה מעולם לא הגיע לסופו והכותרת נתקעה באמצע הדרך. הכלל: אזור ההיצמדות חייב להיות ארוך מטווח האנימציה. **ומלכודת שנייה שנתפסה מיד אחריה**: ריפוד תחתון על אלמנט האב אינו חלק מתיבת התוכן שלו, ו-`position:sticky` נעצר בגבול תיבת התוכן. לכן המרווח שנועד להאריך את ההיצמדות דווקא קיצר אותה, והוא הועבר לתוכן עצמו.

קוד להדבקה

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

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

CSS

/* G70 · כותרת שמתכווצת ומתעגנת לפינה */
.dk{position:relative}
.dk-stage{position:sticky;top:0;height:100vh;pointer-events:none;z-index:5}
/* העוגן הוא הפינה הימנית העליונה, ונקודת הקנה מידה שם, כך שההתכווצות מושכת אליה */
.dk-title{position:absolute;top:26px;right:24px;margin:0;white-space:nowrap;
  font-size:clamp(30px,6vw,84px);font-weight:800;line-height:1;color:var(--ink, #16182b);
  transform-origin:100% 0%;will-change:transform}
/* המרווח יושב על התוכן ולא על הפרק: ריפוד של האב אינו חלק מתיבת התוכן שלו,
   ו-sticky נעצר בגבול תיבת התוכן. מרווח על האב היה מקצר את אזור ההיצמדות. */
.dk-body{margin-top:-100vh;padding:100vh var(--gutter, clamp(24px, 5vw, 96px)) 60vh;max-width:min(760px,92vw);margin-inline:auto}
.dk-body p{font-size:17px;line-height:1.9;color:var(--muted, #6a6d85);margin:0 0 22px}
.dk-body h4{font-size:clamp(20px,2.4vw,30px);margin:40px 0 12px}

HTML

<div class="dk">
  <div class="dk-stage"><h3 class="dk-title">אפיון</h3></div>
  <div class="dk-body">
    <h4>מה קורה בשלב הזה</h4>
    <p>מתחילים בהבנה של העסק ושל הלקוח, ורק אחר כך פותחים כלי עיצוב. זה השלב שקובע אם האתר יביא פניות או רק ייראה טוב, והוא גם השלב שהכי קל לוותר עליו כשממהרים.</p>
    <p>בפועל זו שיחה אחת ממוקדת: מי הלקוח, מה הוא מחפש, מה עוצר אותו מלפנות, ומה הפעולה היחידה שאנחנו רוצים שיעשה. התשובות האלה קובעות את סדר הסקשנים באתר.</p>
    <h4>מה יוצא מזה</h4>
    <p>מסמך קצר עם מפת עמודים, המסרים המרכזיים והקריאה לפעולה. לא מסמך לארכיון אלא מסמך שכותבים לפיו.</p>
    <p>גלול והכותרת למעלה תתכווץ לתווית. גלול חזרה והיא תחזור להיות כותרת מלאה.</p>
  </div>
</div>

JS

gsap.registerPlugin(ScrollTrigger);

(function(){
  const title=document.querySelector(".dk-title");
  const reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
  if(reduce)return;
  // בלי שום מדידה: שני מצבים מוגדרים במלואם, ו-GSAP עושה אינטרפולציה בין אחוזים לפיקסלים.
  // מצב א: הקצה הימני במרכז המסך ואז דחיפה של חצי רוחב, כלומר מרכוז מדויק.
  // מצב ב: העוגן בפינה, ונקודת הקנה מידה שם, ולכן ההתכווצות מושכת אל הפינה.
  gsap.fromTo(title,
    {top:"50%",right:"50%",xPercent:50,yPercent:-50,scale:1},
    {top:"26px",right:"24px",xPercent:0,yPercent:0,scale:.34,ease:"none",
     scrollTrigger:{trigger:".dk",start:"top top",end:"+=70%",scrub:.5,invalidateOnRefresh:true}});
})();