הנפשה של אלמנטים בזמן גלילה באמצעות אנימציות מבוססות גלילה

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

אנימציות שמתבססות על גלילה

תמיכה בדפדפנים

  • Chrome:‏ 115.
  • קצה: 115.
  • Firefox: מאחורי דגל.
  • Safari: לא נתמך.

מקור

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

מדד קריאה בחלק העליון של המסמך, שמופעל על ידי גלילה.

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

התמונות בדף הזה עולות כאשר הן נראות.

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

  • בדפדפנים מודרניים, גלילה מתבצעת בתהליך נפרד, ולכן אירועי גלילה נשלחים באופן אסינכרוני.
  • האנימציות של ה-thread הראשי כפופות ל-jank.

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

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

המושגים החדשים האלה משתלבים עם ה-Web Animations API (WAAPI) ועם CSS Animations API, וכך יורשים את היתרונות שממשקי ה-API הקיימים מעניקים. היכולת הזו כוללת את האפשרות להפעיל אנימציות שמבוססות על גלילה ב-thread הראשי. כן, כדאי לקרוא את זה נכון: עכשיו אפשר ליהנות מאנימציות חלקות ממש שמונעות על ידי גלילה ומדלגות על השרשור הראשי באמצעות כמה שורות קוד נוספות. מה לא אהבת?!

אנימציות באינטרנט, סיכום קצר

אנימציות באינטרנט באמצעות CSS

כדי ליצור אנימציה ב-CSS, מגדירים קבוצה של פריימים מרכזיים באמצעות כלל at-rule‏ @keyframes. מקשרים אותו לרכיב באמצעות המאפיין animation-name, ומגדירים גם animation-duration כדי לקבוע את משך הזמן של האנימציה. יש עוד מאפיינים animation-* בכתב מלא שזמינים – animation-easing-function ו-animation-fill-mode, רק כדי לציין כמה מהם – שאפשר לשלב את כולם בקיצור הדרך animation.

לדוגמה, הנה אנימציה שבה גורמים להגדלה של רכיב בציר X תוך שינוי צבע הרקע שלו:

@keyframes scale-up {
  from {
    background-color: red;
    transform: scaleX(0);
  }
  to {
    background-color: darkred;
    transform: scaleX(1);
  }
}

#progressbar {
  animation: 2.5s linear forwards scale-up;
}

אנימציות באינטרנט באמצעות JavaScript

ב-JavaScript, אפשר להשתמש ב-Web Animations API כדי להשיג בדיוק את אותו הדבר. אפשר לעשות זאת על ידי יצירת מכונות Animation ו-KeyFrameEffect חדשות, או להשתמש בשיטה הקצרה יותר Element animate().

document.querySelector('#progressbar').animate(
  {
    backgroundColor: ['red', 'darkred'],
    transform: ['scaleX(0)', 'scaleX(1)'],
  },
  {
    duration: 2500,
    fill: 'forwards',
    easing: 'linear',
   }
);

התוצאה החזותית הזו של קטע הקוד של JavaScript שלמעלה זהה לגרסה הקודמת של ה-CSS.

צירי זמן של אנימציה

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

במפרט של אנימציות מבוססות גלילה מוגדרים שני סוגים חדשים של צירי זמן שבהם אפשר להשתמש:

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

גלילה בציר הזמן של ההתקדמות

ציר זמן של התקדמות גלילה הוא ציר זמן של אנימציה שמקושר להתקדמות במיקום הגלילה של מאגר גלילה – שנקרא גם scrollport או scroller – לאורך ציר מסוים. היא ממירה מיקום בטווח גלילה לאחוז התקדמות.

מיקום הגלילה ההתחלתי מייצג התקדמות של 0%, ומיקום הגלילה הסופי מייצג התקדמות של 100%. בתצוגה החזותית הבאה אפשר לראות שההתקדמות עולה מ-0% ל-100% כשגוללים את פס ההזזה מלמעלה למטה.

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

✨ רוצים לנסות בעצמכם?

לרוב, מקצרים את 'ציר זמן של התקדמות גלילה' ל'ציר זמן של גלילה'.

הצגת ציר הזמן של ההתקדמות

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

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

ציר הזמן של התקדמות הצפייה מתחיל מהרגע שבו הנושא מתחיל לחפוף לפס ההזזה ומסתיים כשהנושא מפסיק לחפוף לפס ההזזה. בתצוגה הוויזואלית הבאה אפשר לראות שההתקדמות מתחילה להיספר מ-0% כשהנושא נכנס למאגר הגלילה, ומגיעה ל-100% ברגע שהנושא יוצא ממאגר הגלילה.

תצוגה חזותית של ציר הזמן של התקדמות הצפייה. ההתקדמות נספרת מ-0% עד 100% כשהנושא (הקופסה הירוקה) חוצה את פס ההזזה.

✨ רוצים לנסות בעצמכם?

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

שימוש מעשי בצירי זמן של התקדמות גלילה

יצירת ציר זמן אנונימי של התקדמות גלילה ב-CSS

הדרך הקלה ביותר ליצור ציר זמן לגלילה ב-CSS היא להשתמש בפונקציה scroll(). הפעולה הזו יוצרת ציר זמן אנונימי של גלילה שאפשר להגדיר כערך של נכס animation-timeline החדש.

דוגמה:

@keyframes animate-it {  }

.subject {
  animation: animate-it linear;
  animation-timeline: scroll(root block);
}

הפונקציה scroll() מקבלת את הארגומנטים <scroller> ו-<axis>.

הערכים הקבילים לארגומנט <scroller> הם:

  • nearest: המערכת משתמשת בקונטיינר הגלילה הקרוב ביותר של האב (ברירת המחדל).
  • root: נעשה שימוש בחלון התצוגה של המסמך כקונטיינר הגלילה.
  • self: הרכיב עצמו משמש כקונטיינר לגלילה.

הערכים הקבילים לארגומנט <axis> הם:

  • block: שימוש במדד ההתקדמות לאורך ציר הבלוק של קונטיינר הגלילה (ברירת המחדל).
  • inline: נעשה שימוש במדד ההתקדמות לאורך הציר של קונטיינר הגלילה.
  • y: נעשה שימוש במדד ההתקדמות לאורך ציר ה-Y של מאגר הגלילה.
  • x: הפונקציה משתמשת במדדי ההתקדמות לאורך ציר ה-X של מאגר הגלילה.

לדוגמה, כדי לקשר אנימציה לפס ההזזה ברמה הבסיסית בציר הבלוק, הערכים שצריך להעביר אל scroll() הם root ו-block. בסך הכול, הערך הוא scroll(root block).

הדגמה: אינדיקטור של התקדמות בקריאה

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

הדגמה: מדד התקדמות הקריאה.

✨ רוצים לנסות בעצמכם?

מחוון ההתקדמות בקריאה ממוקם בחלק העליון של הדף לפי מיקום קבוע. כדי להשתמש באנימציות מורכבות, לא מתבצעת אנימציה של width, אלא הקטנת הרכיב של הרכיב על ציר ה-X באמצעות transform.

<body>
  <div id="progress"></div>
  …
</body>
@keyframes grow-progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

#progress {
  position: fixed;
  left: 0; top: 0;
  width: 100%; height: 1em;
  background: red;

  transform-origin: 0 50%;
  animation: grow-progress auto linear;
  animation-timeline: scroll();
}

ציר הזמן של האנימציה grow-progress ברכיב #progress מוגדר כציר זמן אנונימי שנוצר באמצעות scroll(). לא ניתנים ארגומנטים ל-scroll(), ולכן היא תשתמש בערכי ברירת המחדל שלה.

פס הגלילה שמוגדר כברירת מחדל למעקב הוא nearest, וציר ברירת המחדל הוא block. כך ניתן לטרגט ביעילות את רכיב הגלילה ברמה הבסיסית (root) כי הוא הגלילה הקרובה ביותר של הרכיב #progress, תוך מעקב אחר כיוון הבלוק שלו.

יצירת ציר זמן של התקדמות גלילה בעל שם ב-CSS

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

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

כדי לשנות את הציר שרוצים לעקוב אחריו, צריך להצהיר גם על המאפיין scroll-timeline-axis. הערכים המותרים זהים לארגומנט <axis> של scroll().

לבסוף, כדי לקשר את האנימציה לציר הזמן של התקדמות הגלילה, מגדירים את המאפיין animation-timeline ברכיב שרוצים להוסיף לו אנימציה לאותו ערך של המזהה שמשמש את scroll-timeline-name.

דוגמה לקוד:

@keyframes animate-it {  }

.scroller {
  scroll-timeline-name: --my-scroller;
  scroll-timeline-axis: inline;
}

.scroller .subject {
  animation: animate-it linear;
  animation-timeline: --my-scroller;
}

אם רוצים, אפשר לשלב את המשאבים scroll-timeline-name ו-scroll-timeline-axis בקיצור הדרך scroll-timeline. לדוגמה:

scroll-timeline: --my-scroller inline;

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

הדגמה: חיווי של שלב בקרוסלה אופקית.

✨ רוצים לנסות בעצמכם?

ה-Markup הבסיסי של גלריה הוא:

<div class="gallery" style="--num-images: 2;">
  <div class="gallery__scrollcontainer">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">…</div>
    <div class="gallery__entry">…</div>
  </div>
</div>

רכיב .gallery__progress ממוקם באופן מוחלט בתוך רכיב העטיפה .gallery. הגודל הראשוני שלו נקבע על ידי המאפיין המותאם אישית --num-images.

.gallery {
  position: relative;
}


.gallery__progress {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 1em;
  transform: scaleX(calc(1 / var(--num-images)));
}

הרכיב .gallery__scrollcontainer מציב את רכיבי ה-.gallery__entry הכלולים בו באופן אופקי, והוא הרכיב שגלול. מעקב אחר מיקום הגלילה יגרום להנפשה של .gallery__progress. כדי לעשות זאת, צריך להפנות לציר הזמן שנקרא 'התקדמות גלילה' --gallery__scrollcontainer.

@keyframes grow-progress {
  to { transform: scaleX(1); }
}

.gallery__scrollcontainer {
  overflow-x: scroll;
  scroll-timeline: --gallery__scrollcontainer inline;
}
.gallery__progress {
  animation: auto grow-progress linear forwards;
  animation-timeline: --gallery__scrollcontainer;
}

יצירת ציר זמן של התקדמות גלילה באמצעות JavaScript

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

  • source: הפניה לאלמנט שרוצים לעקוב אחרי גלילה שלו. משתמשים ב-document.documentElement כדי לטרגט את קובץ הגלילה ברמה הבסיסית (root).
  • axis: קובע איזה ציר יתבצע אחריו מעקב. בדומה לגרסה של CSS, הערכים הקבילים הם block,‏ inline,‏ x ו-y.
const tl = new ScrollTimeline({
  source: document.documentElement,
});

כדי לצרף אותו לאנימציה באינטרנט, מעבירים אותו כנכס timeline ומשמטים כל duration אם יש כזה.

$el.animate({
  opacity: [0, 1],
}, {
  timeline: tl,
});

הדגמה: אינדיקטור ההתקדמות בקריאה, גרסה מעודכנת

כדי ליצור מחדש את אינדיקטור התקדמות הקריאה באמצעות JavaScript, תוך שימוש באותו סימון, צריך להשתמש בקוד ה-JavaScript הבא:

const $progressbar = document.querySelector('#progress');

$progressbar.style.transformOrigin = '0% 50%';
$progressbar.animate(
  {
    transform: ['scaleX(0)', 'scaleX(1)'],
  },
  {
    fill: 'forwards',
    timeline: new ScrollTimeline({
      source: document.documentElement,
    }),
  }
);

התוצאה החזותית זהה בגרסה של ה-CSS: ה-timeline שנוצר עוקב אחרי גלילה ברמה הבסיסית ומגדיל את ה-#progress בציר x מ-0% ל-100% כשגוללים בדף.

✨ רוצים לנסות בעצמכם?

שימוש מעשי בציר הזמן של תצוגת ההתקדמות

יצירת ציר זמן של התקדמות תצוגה אנונימית ב-CSS

כדי ליצור ציר זמן של התקדמות הצפייה, משתמשים בפונקציה view(). הארגומנטים הקבילים שלו הם <axis> ו-<view-timeline-inset>.

  • הערך של <axis> זהה לערך של ציר הזמן של התקדמות הגלילה, והוא קובע איזה ציר יתבצע אחריו מעקב. ערך ברירת המחדל הוא block.
  • בעזרת <view-timeline-inset> אפשר לציין תנועה (חיובית או שלילית) כדי לשנות את הגבולות של הזמן שבו רכיב נחשב כגלוי או לא גלוי. הערך חייב להיות אחוז או auto, כאשר auto הוא ערך ברירת המחדל.

לדוגמה, כדי לקשר אנימציה לרכיב שמצטלב עם פס הגלילה שלה על ציר הבלוק, צריך להשתמש בפונקציה view(block). בדומה ל-scroll(), עליך להגדיר את הערך הזה כערך של הנכס animation-timeline, ולא לשכוח להגדיר את animation-duration ל-auto.

בעזרת הקוד הבא, כל img יהפוך לשקוף בהדרגה כשאזור התצוגה יחצה את אזור התצוגה בזמן הגלילה.

@keyframes reveal {
  from { opacity: 0; }
  to { opacity: 1; }
}

img {
  animation: reveal linear;
  animation-timeline: view();
}

Intermezzo: הצגת הטווחים של ציר הזמן

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

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

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

אלה טווחי ציר הזמן של הצפייה שאפשר לטרגט:

  • cover: מייצג את כל הטווח של ציר הזמן של התקדמות הצפייה.
  • entry: מייצג את הטווח שבו התיבה של חשבון המשתמש נכנסת לטווח החשיפה של התקדמות הצפייה.
  • exit: מייצג את הטווח שבו התיבה של חשבון המשתמש יוצאת מטווח החשיפה של התקדמות הצפייה.
  • entry-crossing: מייצג את הטווח שבו התיבה של חשבון המשתמש חוצה את קצה הגבול.
  • exit-crossing: מייצג את הטווח שבו תיבת החשבון הראשי חוצה את קצה גבול ההתחלה.
  • contain: מייצג את הטווח שבו תיבת חשבון המשתמש נכללת במלואה בטווח החשיפה של התקדמות התצוגה בחלונית הגלילה, או מכסה אותו במלואו. זה תלוי אם הנושא גבוה או נמוך מהפס הגלילה.

כדי להגדיר טווח, צריך להגדיר את הפרמטרים range-start ו-range-end. כל אחד מהם כולל שם טווח (ראו ברשימה למעלה) והרחקה מהטווח כדי לקבוע את המיקום בתוך שם הטווח. בדרך כלל, הערך של range-offset הוא אחוז בטווח שבין 0% ל-100%, אבל אפשר גם לציין אורך קבוע, כמו 20em.

לדוגמה, אם רוצים להפעיל אנימציה מהרגע שבו נושא מסוים נכנס, בוחרים ב-entry 0% כ-range-start. כדי לסיים את התהליך עד שעת הכניסה של הנושא, צריך לבחור entry 100% כערך של קצה הטווח.

ב-CSS, מגדירים את זה באמצעות הנכס animation-range. דוגמה:

animation-range: entry 0% entry 100%;

ב-JavaScript, משתמשים במאפיינים rangeStart ו-rangeEnd.

$el.animate(
  keyframes,
  {
    timeline: tl,
    rangeStart: 'entry 0%',
    rangeEnd: 'entry 100%',
  }
);

הכלי המוטמע בהמשך מאפשר לראות מה מייצג כל שם טווח ואיך האחוזים משפיעים על מיקומי ההתחלה והסיום. מנסים להגדיר את ההתחלה של הטווח ל-entry 0% ואת קצה הטווח ל-cover 50%, ואז גוררים את סרגל הגלילה כדי לראות את תוצאת האנימציה.

הכלי להצגה חזותית של טווחי ציר הזמן, שזמין בכתובת https://goo.gle/view-timeline-range-tool

צפייה בהקלטה

כשתתחילו להתנסות בכלים האלה להצגת טווחי ציר הזמן, תבחינו שאפשר לטרגט טווחים מסוימים באמצעות שני שילובים שונים של שם-טווח + סטייה-טווח. לדוגמה, entry 0%, entry-crossing 0% ו-cover 0% מטרגטים לאותו אזור.

כשהיעדים של range-start ו-range-end הם אותו range-name והם נפרסים על פני כל הטווח – מ-0% עד 100%– אפשר לקצר את הערך ולציין רק את שם הטווח. לדוגמה, אפשר לכתוב מחדש את animation-range: entry 0% entry 100%; כ-animation-range: entry הקצר בהרבה.

הדגמה: חשיפת תמונה

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

הדגמה: הצגת תמונה

✨ כדאי לנסות בעצמכם

האפקט של ההרחבה מתקבל באמצעות נתיב חיתוך עם אנימציה. קוד ה-CSS שמשמש לאפקט הזה הוא:

@keyframes reveal {
  from { opacity: 0; clip-path: inset(0% 60% 0% 50%); }
  to { opacity: 1; clip-path: inset(0% 0% 0% 0%); }
}

.revealing-image {
  animation: auto linear reveal both;
  animation-timeline: view();
  animation-range: entry 25% cover 50%;
}

יצירת ציר זמן של התקדמות התצוגה בעל שם ב-CSS

בדומה לגרסאות בעלות שם של צירי זמן לגלילה, אפשר גם ליצור צירי זמן של תצוגות עם שם. במקום בנכסי scroll-timeline-*, משתמשים בווריאציות עם הקידומת view-timeline-, כלומר view-timeline-name ו-view-timeline-axis.

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

הדגמה: חשיפת תמונה, גרסה מעודכנת

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

.revealing-image {
  view-timeline-name: --revealing-image;
  view-timeline-axis: block;

  animation: auto linear reveal both;
  animation-timeline: --revealing-image;
  animation-range: entry 25% cover 50%;
}

באמצעות view-timeline-name: revealing-image, המערכת תעקוב אחרי הרכיב בתוך סרגל ההזזה הקרוב ביותר. לאחר מכן, אותו ערך ישמש כערך של המאפיין animation-timeline. הפלט החזותי זהה לזה שהיה לפני כן.

✨ רוצים לנסות בעצמכם?

יצירת ציר זמן של התקדמות הצפייה ב-JavaScript

כדי ליצור צפייה בציר הזמן ב-JavaScript, צריך ליצור מופע חדש של המחלקה ViewTimeline. מעבירים שקית נכסים עם subject שרוצים לעקוב אחריו, axis ו-inset.

  • subject: הפניה לאלמנט שרוצים לעקוב אחריו בתוך פס ההזזה שלו.
  • axis: הציר שרוצים לעקוב אחריו. בדומה לגרסה של CSS, הערכים הקבילים הם block,‏ inline,‏ x ו-y.
  • inset: התאמה של חלון הגלילה פנימה (חיובי) או החוצה (שלילי) כשמגדירים אם התיבה מוצגת.
const tl = new ViewTimeline({
  subject: document.getElementById('subject'),
});

כדי לצרף אותו לאנימציה באינטרנט, מעבירים אותו כנכס timeline ומשמטים כל duration אם יש כזה. אפשר גם להעביר את פרטי הטווח באמצעות המאפיינים rangeStart ו-rangeEnd.

$el.animate({
  opacity: [0, 1],
}, {
  timeline: tl,
  rangeStart: 'entry 25%',
  rangeEnd: 'cover 50%',
});

✨ כדאי לנסות בעצמכם

עוד דברים שכדאי לנסות

צירוף לטווחים מרובים של ציר הזמן של התצוגה באמצעות קבוצה אחת של נקודות מפתח

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

הדגמה: רשימת אנשי קשר

✨ רוצים לנסות בעצמכם?

בהדגמה הזו, כל רכיב מקבל תצוגה של ציר זמן אחד שעוקב אחרי האלמנט כשחוצה את סרגל הגלילה, אבל מצורפות אליו שתי אנימציות. האנימציה animate-in מצורפת לטווח entry בציר הזמן, והאנימציה animate-out מצורפת לטווח exit בציר הזמן.

@keyframes animate-in {
  0% { opacity: 0; transform: translateY(100%); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes animate-out {
  0% { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-100%); }
}

#list-view li {
  animation: animate-in linear forwards,
             animate-out linear forwards;
  animation-timeline: view();
  animation-range: entry, exit;
}

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

@keyframes animate-in-and-out {
  entry 0%  {
    opacity: 0; transform: translateY(100%);
  }
  entry 100%  {
    opacity: 1; transform: translateY(0);
  }
  exit 0% {
    opacity: 1; transform: translateY(0);
  }
  exit 100% {
    opacity: 0; transform: translateY(-100%);
  }
}

#list-view li {
  animation: linear animate-in-and-out;
  animation-timeline: view();
}

מאחר שמפתחות ה-keyframe מכילים את פרטי הטווח, אין צורך לציין את animation-range. התוצאה זהה לחלוטין.

✨ רוצים לנסות בעצמכם?

צירוף לציר זמן של גלילה שאינו אב קדמון

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

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

לדוגמה:

.parent {
  timeline-scope: --tl;
}
.parent .scroller {
  scroll-timeline: --tl;
}
.parent .scroller ~ .subject {
  animation: animate linear;
  animation-timeline: --tl;
}

בקטע הקוד הזה:

  • הרכיב .parent מצהיר על ציר זמן בשם --tl. כל צאצא שלו יכול למצוא אותו ולהשתמש בו כערך עבור הנכס animation-timeline.
  • למעשה, הרכיב .scroller מגדיר ציר זמן גלילה בשם --tl. כברירת מחדל, הוא יהיה גלוי רק לצאצאים שלו, אבל מכיוון ש-.parent מוגדר כ-scroll-timeline-root, הוא מצורף אליו.
  • הרכיב .subject משתמש בציר הזמן --tl. הוא עולה במורד עץ האב הקדמון ומוצא את --tl ב-.parent. כשה---tl ב-.parent מפנה אל --tl מתוך .scroller, .subject מאפשר לעקוב אחרי ציר הזמן של התקדמות הגלילה ב-.scroller.

במילים אחרות, אפשר להשתמש ב-timeline-root כדי להעביר ציר זמן אל אב קדמון (הפעולה הזו נקראת גם העלאה), כדי שכל הצאצאים של האב הקדמון יוכלו לגשת אליו.

אפשר להשתמש במאפיין timeline-scope גם בכרונולוגיות גלילה וגם בכרונולוגיות תצוגה.

עוד הדגמות ומשאבים

כל ההדגמות במאמר הזה בנושא המיני-אתר שמבוסס על גלילה ממוקדת-animations.style. באתר יש עוד הרבה הדגמות שממחישות את האפשרויות שאפשר ליצור באמצעות אנימציות שמבוססות על גלילה.

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

הדגמה: Cover Flow

✨ רוצים לנסות בעצמכם?

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

הדגמה: ערימה של כרטיסים.

✨ כדאי לנסות בעצמכם

בנוסף, ב- scroll-driven-animations.style יש אוסף כלים, כמו התצוגה החזותית של התקדמות טווח ציר הזמן של התצוגה, שצוינה קודם לכן בפוסט הזה.

אנימציות שמבוססות על גלילה מפורטות גם במה חדש באנימציות באינטרנט ב-Google I/O 2023.