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

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

פורסם: 5 במאי 2023

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

Browser Support

  • Chrome: 115.
  • Edge: 115.
  • Firefox: behind a flag.
  • Safari: 26.

Source

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

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

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

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

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

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

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

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

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

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

כדי ליצור אנימציה ב-CSS, מגדירים קבוצה של מסגרות מפתח באמצעות @keyframes at-rule. מקשרים אותו לרכיב באמצעות המאפיין 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 כשהדף נטען, ומתחיל להתקדם ככל שהזמן עובר. זהו ציר הזמן של האנימציה שמוגדר כברירת מחדל, ועד עכשיו זה היה ציר הזמן היחיד של האנימציה שהייתה לכם גישה אליו.

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

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

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

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

מיקום ההתחלה של הגלילה מייצג התקדמות של 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).

הדגמה: אינדיקטור לגבי מצב ההתקדמות בקריאת התוכן

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

הדגמה: אינדיקטור לגבי מצב ההתקדמות בקריאת התוכן.

✨ נסו בעצמכם

אינדיקטור ההתקדמות בקריאת התוכן ממוקם בחלק העליון של הדף באמצעות position fixed. כדי להשתמש באנימציות מורכבות, לא מונפש הרכיב 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(), ולכן היא תחזור לערכי ברירת המחדל שלה.

ברירת המחדל של רכיב ה-scroller למעקב היא 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 מתבצעת על ידי מעקב אחרי מיקום הגלילה שלו. כדי לעשות את זה, מפנים לציר הזמן שנקרא Scroll Progress Timeline --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. ההיסטור של הטווח הוא בדרך כלל אחוז שנע בין 0% ל-100%, אבל אפשר גם לציין אורך קבוע כמו 20em.

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

הכלי View Timeline Ranges Visualizer, שזמין בכתובת 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.

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

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

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

✨ נסו בעצמכם

אפקט ההרחבה מושג באמצעות clip-path עם אנימציה. ה-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();
}

מכיוון שפרטי הטווח כלולים בפריים המרכזי, אין צורך לציין את 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.