1. לפני שמתחילים
אנימציות המונעות גלילה מאפשרות לשלוט בהפעלה של אנימציה על סמך מיקום הגלילה של מאגר הגלילה. כלומר, כשגוללים למעלה או למטה, האנימציה עוברת קדימה או אחורה. בנוסף, באמצעות אנימציות מבוססות גלילה ניתן גם לשלוט באנימציה על סמך מיקום הרכיב בתוך מאגר הגלילה שלו. כך ניתן ליצור אפקטים מעניינים, כגון תמונת רקע של פרלקס, סרגלי התקדמות של גלילה ותמונות שחושפים את עצמן ברגע שהן מזוהות.
הגרסה החדשה של Chrome 115 תומכת בקבוצה של מחלקות JavaScript ומאפייני CSS שמאפשרים ליצור בקלות אנימציות המבוססות על גלילה. ממשקי ה-API החדשים האלה פועלים בשילוב עם ממשקי ה-API הקיימים של אנימציות אינטרנט ואנימציות של CSS.
בשיעור הזה ב-Codelab אפשר ללמוד איך ליצור אנימציות שמונעות גלילה באמצעות CSS. השלמת ה-Codelab הזו תכיר לכם את מאפייני ה-CSS החדשים הרבים שהוצגו בתכונה המלהיבה הזו, כמו scroll-timeline
, view-timeline
, animation-timeline
ו-animation-range
.
מה תלמדו
- איך ליצור אפקט לרקע של פרלקס באמצעות מקש Scroll Time (ציר הזמן) ב-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%;
}
}
- עכשיו מחברים את תמונות המפתח הבאות לרכיב הגוף:
src/styles.css
body {
animation: 1s linear move-background;
}
באמצעות הקוד הזה, האנימציה move-background
מתווספת לרכיב הגוף. נכס animation-duration
שלו מוגדר לשנייה אחת, והוא משתמש בהכאה ל-linear
.
קישור האנימציה להתקדמות הגלילה של הרמה הבסיסית (root) באמצעות ציר זמן אנונימי של התקדמות הגלילה
הדרך הקלה ביותר ליצור ציר זמן עם התקדמות הגלילה היא להשתמש בפונקציה scroll()
. הפעולה הזו יוצרת ציר זמן אנונימי עם התקדמות הגלילה, שאפשר להגדיר אותו כערך של המאפיין animation-timeline
.
הפונקציה scroll()
מקבלת גם את הארגומנט <scroller>
וגם את הארגומנט <axis>
.
הערכים הקבילים לארגומנט <scroller>
הם:
nearest
משתמשת במאגר הגלילה של ישות האב הקרובה ביותר (ברירת מחדל).root
משתמש באזור התצוגה של המסמך בתור מאגר הגלילה.self
משתמש ברכיב עצמו כמאגר גלילה.
הערכים הקבילים לארגומנט <axis>
הם:
block
משתמשת במדידת ההתקדמות לאורך ציר הבלוקים של מאגר הגלילה (ברירת מחדל).inline
משתמשת במדידת ההתקדמות לאורך הציר המוטבע של מאגר הגלילה.y
משתמשת במדידת ההתקדמות לאורך ציר ה-Y של מאגר הגלילה.x
משתמשת במדידת ההתקדמות לאורך ציר ה-X של מאגר הגלילה.
כדי לקשר את האנימציה לגלילה ברמה הבסיסית (root) בציר הבלוקים, הערכים שיועברו אל scroll()
הם root
ו-block
. יחד, הערך הוא scroll(root block)
.
- מגדירים את
scroll(root block)
כערך המאפייןanimation-timeline
בגוף. - בנוסף, מכיוון שאין הגיון ב
animation-duration
שמבוטאת בשניות, יש להגדיר את משך הזמן ל-auto
. אם לא מציינים ערך שלanimation-duration
, ברירת המחדל שלו היאauto
.
src/styles.css
body {
animation: linear move-background;
animation-duration: auto;
animation-timeline: scroll(root block);
}
מכיוון שגלילה ברמה הבסיסית היא גם גליל ההורה הקרוב ביותר של רכיב הגוף, אפשר להשתמש גם בערך 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. יצירת סרגל התקדמות לגלריית התמונות
בדף יש קרוסלה אופקית שצריך סרגל התקדמות כדי לציין באיזו תמונה אתם צופים כרגע.
תגי העיצוב של הקרוסלה נראים כך:
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. יוצרים אנימציה של תמונות הגלריה בזמן הכניסה לתבנית הגלילה ויציאה ממנה
עמעום בתמונות הגלריה
הגדרה של ציר זמן אנונימי להתקדמות
אפקט נחמד להוסיף הוא עמעום בתמונות הגלריה ברגע שהן נראות. כדי לעשות את זה, אפשר להשתמש בציר הזמן של צפייה בהתקדמות.
כדי ליצור ציר זמן עם התקדמות צפייה, אפשר להשתמש בפונקציה 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
של הנושא, אפשר להשתמש במאפיין ה-CSSanimation-range
כדי להגביל את זמני ההפעלה של האנימציה.
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. יוצרים אנימציה של תמונות הגלריה בזמן הכניסה לחלונית הגלילה ויציאה ממנה, באמצעות קבוצה אחת של תמונות מפתח
הכיסוי לקבוצה אחת של תמונות מפתח
במקום לצרף שתי אנימציות לטווחים שונים, אפשר ליצור קבוצה אחת של תמונות מפתח שכבר מכילה את פרטי הטווח.
הצורה של תמונות המפתח נראית כך:
@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.
מידע נוסף
מקורות: