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 של קונטיינר הגלילה.
כדי לקשר את האנימציה לרכיב הגלילה הבסיסי בציר הבלוק, הערכים שצריך להעביר ל-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.
מידע נוסף
מקורות מידע: