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

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

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

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

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

מקור

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

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

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

התמונות בדף הזה מופיעות בהדרגה כשהן נכנסות לתצוגה.

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

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

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

המושגים החדשים האלה משתלבים עם Web Animations API‏ (WAAPI) ו-CSS Animations API הקיימים, ומאפשרים להם לרשת את היתרונות של ממשקי ה-API הקיימים האלה. היכולת הזו כוללת את האפשרות להפעיל אנימציות שמבוססות על גלילה ב-thread הראשי. כן, קראתם נכון: עכשיו אפשר ליצור אנימציות חלקות כתער, שמתבססות על גלילה, שפועלות ב-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. כך אפשר לטרגט ביעילות את גלילה ברמה הבסיסית, כי זהו רכיב הגלילה הקרוב ביותר לרכיב #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 כדי לטרגט את סרגל הגלילה ברמה הבסיסית.
  • 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();
}

אינטרמצו: הצגת טווחי ציר הזמן

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

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

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

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

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

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

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

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

animation-range: entry 0% entry 100%;

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

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

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

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

צפייה בהקלטה

כשתתחילו להתנסות בכלים האלה להצגת טווחי ציר הזמן, תבחינו שאפשר לטרגט טווחים מסוימים באמצעות שני שילובים שונים של range-name + range-offset. לדוגמה, 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 גם בכרונולוגיות גלילה וגם בכרונולוגיות תצוגה.

הדגמות ומשאבים נוספים

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

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

הדגמה: Cover Flow

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

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

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

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

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

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