1. לפני שמתחילים
אנימציות מבוססות-גלילה מאפשרות לכם לשלוט בהפעלה של אנימציה על סמך מיקום הגלילה של מאגר גלילה. כלומר, כשגוללים למעלה או למטה, האנימציה מתקדמת או חוזרת אחורה. בנוסף, בעזרת אנימציות מבוססות-גלילה אפשר גם לשלוט באנימציה על סמך המיקום של רכיב בתוך מאגר הגלילה שלו. כך תוכלו ליצור אפקטים מעניינים כמו תמונת רקע עם אפקט פרלקסה, סרגלי התקדמות של גלילה ותמונות שנחשפות כשהן נכנסות לתצוגה.
ב-Chrome 115 נוספה תמיכה בקבוצה של מחלקות JavaScript ומאפייני CSS שמאפשרים ליצור בקלות אנימציות הצהרתיות מבוססות גלילה. ממשקי ה-API החדשים האלה פועלים בשילוב עם ממשקי ה-API הקיימים של Web Animations ו-CSS Animations.
ב-Codelab הזה נלמד איך ליצור אנימציות מבוססות גלילה באמצעות CSS. בסיום ה-codelab הזה, תכירו את הרבה מאפייני CSS חדשים שהוצגו בתכונה המעניינת הזו, כמו scroll-timeline, view-timeline, animation-timeline ו-animation-range.
מה תלמדו
- איך יוצרים אפקט רקע של פרלקסה באמצעות ציר זמן של גלילה ב-CSS.
- איך יוצרים פס התקדמות עם ציר זמן של גלילה ב-CSS.
- איך יוצרים אפקט של חשיפת תמונה באמצעות ציר זמן של תצוגה ב-CSS.
- איך לטרגט סוגים שונים של טווחי תאריכים בציר הזמן של התצוגה בשירות CSS.
הדרישות
אחד משילובי המכשירים הבאים:
- גרסה עדכנית של Chrome (גרסה 115 ואילך) ב-ChromeOS, macOS או Windows, כשההגדרה 'תכונות ניסיוניות של פלטפורמת האינטרנט' מופעלת.
- הבנה בסיסית של HTML
- הבנה בסיסית של CSS, במיוחד אנימציות ב-CSS
2. להגדרה
כל מה שצריך לפרויקט הזה זמין במאגר GitHub. כדי להתחיל, משכפלים את הקוד ופותחים אותו בסביבת הפיתוח המועדפת.
- פותחים כרטיסייה חדשה בדפדפן ועוברים אל https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab.
- משכפלים את המאגר.
- פותחים את הקוד בסביבת הפיתוח המשולבת (IDE) המועדפת.
- מריצים את הפקודה
npm installכדי להתקין את יחסי התלות. - מריצים את הפקודה
npm startועוברים אל http://localhost:3000/. - לחלופין, אם npm לא מותקן, פותחים את הקובץ
src/index.htmlב-Chrome.
3. מידע על ציר זמן של אנימציה
כברירת מחדל, אנימציה שמצורפת לרכיב פועלת בציר הזמן של המסמך. כלומר, כשטעינת הדף מתבצעת, האנימציה מתקדמת עם הזמן. זהו ציר הזמן של האנימציה שמוגדר כברירת מחדל, ועד עכשיו זה היה ציר הזמן היחיד של האנימציה שהייתה לכם גישה אליו.
באמצעות אנימציות מבוססות-גלילה, מקבלים גישה לשני סוגים חדשים של ציר זמן:
- גלילה בציר הזמן של ההתקדמות
- צפייה בציר הזמן של ההתקדמות
ב-CSS, אפשר לצרף את ציר הזמן הזה לאנימציה באמצעות המאפיין animation-timeline. כדאי לעיין בלוחות הזמנים החדשים ולראות מה ההבדלים ביניהם.
גלילה בציר הזמן של ההתקדמות
ציר זמן של התקדמות הגלילה הוא ציר זמן של אנימציה שמקושר להתקדמות במיקום הגלילה של מאגר גלילה – שנקרא גם אזור גלילה או רכיב גלילה – לאורך ציר מסוים. הפונקציה ממירה מיקום בטווח גלילה לאחוז התקדמות לאורך ציר זמן.
מיקום ההתחלה של הגלילה מייצג התקדמות של 0%, ומיקום הסיום של הגלילה מייצג התקדמות של 100%. באיור הבא אפשר לראות שההתקדמות נספרת מ-0% עד 100% כשגוללים למטה בסרגל הגלילה.
צפייה בציר הזמן של ההתקדמות
ציר הזמן הזה מקושר להתקדמות היחסית של רכיב מסוים בתוך מאגר גלילה. בדומה לציר זמן של התקדמות הגלילה, מתבצע מעקב אחרי היסט הגלילה של רכיב לגלילה. בניגוד לציר זמן של התקדמות הגלילה, ההתקדמות נקבעת לפי המיקום היחסי של הנושא באזור הגלילה. ההגדרה הזו דומה ל-IntersectionObserver, שמתעדת את מידת הנראות של אלמנט באזור הגלילה. אם הרכיב לא גלוי באזור הגלילה, הוא לא נמצא בחיתוך. אם הוא גלוי בתוך אזור הגלילה – אפילו אם רק חלק קטן ממנו גלוי – הוא מצטלב.
ציר הזמן של התקדמות הצפייה מתחיל ברגע שהנושא מתחיל לחתוך את רכיב הגלילה ומסתיים כשהנושא מפסיק לחתוך את רכיב הגלילה. באיור הבא אפשר לראות שהספירה של ההתקדמות מתחילה מ-0% כשהנושא נכנס למאגר הגלילה, ומגיעה ל-100% כשהוא יוצא ממנו.
כברירת מחדל, אנימציה שמקושרת לציר הזמן של התקדמות הצפייה מצורפת לכל טווח הזמן שלו. הזמן הזה מתחיל ברגע שהנושא נכנס לאזור הגלילה ומסתיים כשהנושא יוצא מאזור הגלילה.
אפשר גם לקשר אותו לחלק ספציפי בציר הזמן של התקדמות הצפייה על ידי ציון הטווח שאליו הוא צריך להיות מצורף. לדוגמה, רק כשהנושא נכנס לאזור הגלילה. באיור הבא, ספירת ההתקדמות מתחילה מ-0% כשהנושא נכנס למאגר הגלילה, אבל מגיעה ל-100% כבר מהרגע שבו הוא חותך את המאגר לגמרי.
הטווחים האפשריים של ציר הזמן של הצפייה שאפשר לטרגט הם cover, contain, entry, exit, entry-crossing ו-exit-crossing. ההסבר על הטווחים האלה מופיע בהמשך ה-Codelab הזה, אבל אם אתם רוצים לדעת מה כל טווח מייצג, אתם יכולים להשתמש בכלי שזמין בכתובת https://goo.gle/view-timeline-range-tool.
4. יצירת אפקט רקע של פרלקסה
האפקט הראשון שמוסיפים לדף הוא אפקט רקע פרלקסי בתמונת הרקע הראשית. כשגוללים למטה בדף, תמונת הרקע אמורה לזוז, אבל במהירות שונה. לצורך כך, מסתמכים על ציר זמן של התקדמות הגלילה.
כדי להטמיע את השינוי הזה, צריך לבצע שני שלבים:
- ליצור אנימציה שמשנה את המיקום של תמונת הרקע.
- מקשרים את האנימציה להתקדמות הגלילה במסמך.
יצירת האנימציה
- כדי ליצור את האנימציה, משתמשים בקבוצה רגילה של מסגרות מפתח. בתוכה, מעבירים את מיקום הרקע מ-0% לאורך ל-100%:
src/styles.css
@keyframes move-background {
from {
background-position: 50% 0%;
}
to {
background-position: 50% 100%;
}
}
- עכשיו מצרפים את מסגרות המפתח האלה לרכיב body:
src/styles.css
body {
animation: 1s linear move-background;
}
הקוד הזה מוסיף את האנימציה move-background לרכיב body. המאפיין animation-duration שלו מוגדר לשנייה אחת, והוא משתמש ב-linear easing.
קישור האנימציה להתקדמות הגלילה של רכיב הבסיס באמצעות ציר זמן אנונימי של התקדמות הגלילה
הדרך הקלה ביותר ליצור ציר זמן של התקדמות הגלילה היא באמצעות הפונקציה scroll(). פעולה כזו יוצרת ציר זמן אנונימי של התקדמות הגלילה, שאפשר להגדיר כערך של המאפיין animation-timeline.
הפונקציה scroll() מקבלת ארגומנטים של <scroller> ושל <axis>.
הערכים הקבילים לארגומנט <scroller> הם:
-
nearest. משתמש בקונטיינר הגלילה הקרוב ביותר ברמת ההורה (ברירת מחדל). -
root. משתמש באזור התצוגה של המסמך כקונטיינר הגלילה. -
self. משתמש ברכיב עצמו כקונטיינר הגלילה.
הערכים הקבילים לארגומנט <axis> הם:
-
block. משתמש במדד ההתקדמות לאורך ציר הבלוק של קונטיינר הגלילה (ברירת מחדל). -
inline. משתמש במדד ההתקדמות לאורך הציר המוטבע של קונטיינר הגלילה. -
y. משתמש במדד ההתקדמות לאורך ציר Y של קונטיינר הגלילה. -
x. משתמש במדד ההתקדמות לאורך ציר X של קונטיינר הגלילה.
כדי לקשר את האנימציה לרכיב הגלילה הבסיסי בציר הבלוק, הערכים שצריך לקבוע ערך (pass) ל-scroll() הם root ו-block. הערך המלא הוא scroll(root block).
- מגדירים את הערך
scroll(root block)למאפייןanimation-timelineבתג body. - בנוסף, מכיוון שמשך זמן של
animation-durationבשניות לא הגיוני, צריך להגדיר את משך הזמן כ-auto. אם לא מצייניםanimation-duration, ברירת המחדל היאauto.
src/styles.css
body {
animation: linear move-background;
animation-duration: auto;
animation-timeline: scroll(root block);
}
מכיוון שרכיב הגלילה הבסיסי הוא גם רכיב הגלילה הקרוב ביותר לרכיב body, אפשר להשתמש גם בערך nearest:
src/styles.css
body {
animation: linear move-background;
animation-duration: auto;
animation-timeline: scroll(nearest block);
}
מכיוון ש-nearest ו-block הם ערכי ברירת המחדל, אפשר גם להשמיט אותם. במקרה כזה, אפשר לפשט את הקוד כך:
src/styles.css
body {
animation: linear move-background;
animation-duration: auto;
animation-timeline: scroll();
}
בדיקת השינויים
אם הכול עבר בצורה חלקה, אמור להופיע המסך הבא:
אם לא, כדאי לעיין בענף solution-step-1 של הקוד.
5. יצירת סרגל התקדמות לגלריית התמונות
בדף יש קרוסלה אופקית שצריך להוסיף לה סרגל התקדמות כדי לציין איזו תמונה מוצגת כרגע.
קוד ה-markup של הקרוסלה נראה כך:
src/index.html
<div class="gallery">
<div class="gallery__scrollcontainer" style="--num-images: 3;">
<div class="gallery__progress"></div>
<div class="gallery__entry">
...
</div>
<div class="gallery__entry">
...
</div>
<div class="gallery__entry">
...
</div>
</div>
</div>
פריים המפתח של סרגל ההתקדמות כבר מוגדרים ונראים כך:
src/styles.css
@keyframes adjust-progress {
from {
transform: scaleX(calc(1 / var(--num-images)));
}
to {
transform: scaleX(1);
}
}
צריך לצרף את האנימציה הזו ל .רכיב gallery__progress עם ציר זמן של התקדמות הגלילה. כפי שמוצג בשלב הקודם, אפשר לעשות זאת באמצעות יצירה של ציר זמן אנונימי של התקדמות הגלילה באמצעות הפונקציה scroll():
src/styles.css
.gallery__progress {
animation: linear adjust-progress;
animation-duration: auto;
animation-timeline: scroll(nearest inline);
}
למרות שנדמה שהקטע הזה של הקוד אמור לפעול, הוא לא פועל בגלל האופן שבו מתבצעים חיפושים אוטומטיים של מאגרי גלילה באמצעות nearest. כשמחפשים את רכיב הגלילה הקרוב ביותר, הרכיב יתייחס רק לרכיבים שיכולים להשפיע על המיקום שלו. מכיוון שהמיקום של .gallery__progress הוא מוחלט, רכיב האב הראשון שיקבע את המיקום שלו הוא הרכיב .gallery, כי הוחל עליו המאפיין position: relative. כלומר, הרכיב .gallery__scrollcontainer – שהוא רכיב הגלילה שצריך להיות ממוקד – לא נלקח בחשבון במהלך החיפוש האוטומטי הזה.
כדי לעקוף את הבעיה, יוצרים ציר זמן של התקדמות הגלילה עם שם ברכיב .gallery__scrollcontainer ומקשרים אליו את הרכיב .gallery__progress באמצעות השם הזה.
יצירה וקישור של ציר זמן עם שם למעקב אחר התקדמות הגלילה
כדי ליצור ציר זמן עם שם של התקדמות הגלילה ברכיב, מגדירים את מאפיין ה-CSS scroll-timeline-name במאגר הגלילה לערך הרצוי. הערך חייב להתחיל ב---.
הגלריה נגללת אופקית, ולכן צריך להגדיר גם את המאפיין scroll-timeline-axis. הערכים המותרים זהים לארגומנט <axis> של scroll().
לבסוף, כדי לקשר את האנימציה לציר הזמן של התקדמות הגלילה, מגדירים את המאפיין animation-timeline ברכיב שרוצים להנפיש לאותו ערך של המזהה שמשמש ל-scroll-timeline-name.
- משנים את קובץ
styles.cssכך שיכלול את השורות הבאות:
src/styles.css
.gallery__scrollcontainer {
/* Create the gallery-is-scrolling timeline */
scroll-timeline-name: --gallery-is-scrolling;
scroll-timeline-axis: inline;
}
.gallery__progress {
animation: linear adjust-progress;
animation-duration: auto;
/* Set gallery-is-scrolling as the timeline */
animation-timeline: --gallery-is-scrolling;
}
בדיקת השינויים
אם הכול עבר בצורה חלקה, אמור להופיע המסך הבא:
אם לא, כדאי לעיין בענף solution-step-2 של הקוד.
6. הוספת אנימציה לתמונות בגלריה כשהן נכנסות ל-scrollport ויוצאות ממנו
הוספת אפקט הדרגתי של כניסה לתמונות בגלריה
הגדרה של ציר זמן אנונימי של התקדמות הצפייה
אפקט נחמד שאפשר להוסיף הוא דהייה של תמונות הגלריה כשהן נכנסות לתצוגה. לשם כך, אפשר להשתמש בציר זמן של התקדמות הצפייה.
כדי ליצור ציר זמן של התקדמות הצפייה, אפשר להשתמש בפונקציה view(). הארגומנטים הקבילים הם <axis> ו-<view-timeline-inset>.
- הערך
<axis>זהה לערך בציר הזמן של התקדמות הגלילה, והוא מגדיר את הציר למעקב. - בעזרת
<view-timeline-inset>, אפשר לציין היסט (חיובי או שלילי) כדי להתאים את הגבולות כשאלמנט נחשב כגלוי או לא גלוי.
- פריים המפתח כבר נמצאים במקום, אז צריך רק לצרף אותם. כדי לעשות את זה, יוצרים ציר זמן של התקדמות הצפייה בכל רכיב
.gallery__entry.
src/styles.css
@keyframes animate-in {
from {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
to {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
}
.gallery__entry {
animation: linear animate-in;
animation-duration: auto;
animation-timeline: view(inline);
}
הגבלת הטווח של ציר זמן להתקדמות הצפייה
אם שומרים את ה-CSS וטוענים את הדף, רואים שהאלמנטים נכנסים בהדרגה לתצוגה, אבל משהו לא תקין. הם מתחילים עם אטימות 0 כשהם לא מוצגים בכלל, ומגיעים לאטימות 1 רק כשהם יוצאים מהתצוגה.
הסיבה לכך היא שטווח ברירת המחדל של ציר הזמן של התקדמות הצפייה הוא הטווח המלא. הטווח הזה נקרא cover.
- כדי לטרגט רק את הטווח
entryשל הנושא, משתמשים במאפייןanimation-rangeCSS כדי להגביל את הזמן שבו האנימציה תפעל.
src/styles.css
.gallery__entry {
animation: linear fade-in;
animation-duration: auto;
animation-timeline: view(inline);
animation-range: entry 0% entry 100%;
}
האנימציה פועלת עכשיו מ-entry 0% (הנושא עומד להיכנס לגלולן) עד entry 100% (הנושא נכנס במלואו לגלולן).
אלו טווחי הזמן האפשריים של ציר הזמן:
-
cover. מייצג את הטווח המלא של ציר הזמן של התקדמות הצפייה. -
entry. מייצג את הטווח שבו התיבה הראשית נכנסת לטווח הנראות של התקדמות הצפייה. -
exit. מייצג את הטווח שבמהלכו התיבה הראשית יוצאת מטווח הנראות של התקדמות הצפייה. -
entry-crossing. מייצג את הטווח שבו התיבה הראשית חוצה את קצה הגבול. -
exit-crossing. מייצג את הטווח שבמהלכו התיבה הראשית חוצה את קצה הגבול של ההתחלה. -
contain. מייצג את הטווח שבמהלכו התיבה הראשית מוכלת באופן מלא בטווח הנראות של התקדמות הצפייה שלה בתוך אזור הגלילה, או מכסה אותו באופן מלא. זה תלוי אם הנושא גבוה או נמוך יותר מהאזור שניתן לגלילה.
אפשר להשתמש בכלי שנמצא בכתובת https://goo.gle/view-timeline-range-tool כדי לראות מה כל טווח מייצג ואיך אחוזי ההתחלה והסיום משפיעים על המיקומים.
- טווח ההתחלה וטווח הסיום זהים כאן, וההיסטים שמוגדרים כברירת מחדל נמצאים בשימוש, לכן אפשר לפשט את
animation-rangeלשם אחד של טווח אנימציה:
src/styles.css
.gallery__entry {
animation: linear animate-in;
animation-duration: auto;
animation-timeline: view(inline);
animation-range: entry;
}
הוספת אפקט דהייה לתמונות בגלריה
- כדי ליצור אפקט הדרגתי של העלמת התמונות כשהן יוצאות מרכיב הגלילה, אפשר להשתמש באותה שיטה כמו באנימציה של הכניסה, אבל לטרגט טווח אחר.
src/styles.css
@keyframes animate-out {
from {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
to {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
}
.gallery__entry {
animation: linear animate-in, linear animate-out;
animation-duration: auto;
animation-timeline: view(inline);
animation-range: entry, exit;
}
מסגרות המפתח animate-in יחולו על הטווח entry ומסגרות המפתח animate-out יחולו על הטווח exit.
בדיקת השינויים
אם הכול עבר בצורה חלקה, אמור להופיע המסך הבא:
אם לא, כדאי לעיין בענף solution-step-3 של הקוד.
7. ליצור אנימציה לתמונות בגלריה כשהן נכנסות ל-scrollport ויוצאות ממנו, באמצעות קבוצה אחת של מסגרות מפתח
היתרונות של שימוש במערך אחד של פריימים מרכזיים
במקום לצרף שתי אנימציות לטווחים שונים, אפשר ליצור קבוצה אחת של מסגרות מפתח שכבר מכילה את פרטי הטווח.
הצורה של מסגרות המפתח נראית כך:
@keyframes keyframes-name {
range-name range-offset {
...
}
range-name range-offset {
...
}
}
- משלבים את הפריימים המרכזיים של ההנמכה וההגברה באופן הבא:
src/styles.css
@keyframes animate-in-and-out {
entry 0% {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
entry 90% {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
exit 10% {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
exit 100% {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
}
- אם פרטי הטווח מופיעים בפריים המרכזי, אין יותר צורך לציין את
animation-rangeבנפרד. מצרפים את פריים המפתח כמאפייןanimation.
src/styles.css
.gallery__entry {
animation: linear animate-in-and-out both;
animation-duration: auto;
animation-timeline: view(inline);
}
בדיקת השינויים
אם הכול עבר בצורה חלקה, התוצאה צריכה להיות זהה לתוצאה מהשלב הקודם. אם לא, כדאי לעיין בענף solution-step-4 של הקוד.
8. מעולה!
סיימתם את ה-Codelab הזה ועכשיו אתם יודעים איך ליצור ציר זמן של התקדמות הגלילה וציר זמן של התקדמות הצפייה ב-CSS.
מידע נוסף
מקורות מידע: