תנועה היא חלק מרכזי בכל חוויה דיגיטלית, והיא מנחה את המשתמש מאינטראקציה אחת לאחרת. עם זאת, יש כמה פערים באנימציות חלקות בפלטפורמת האינטרנט. התכונות האלה כוללות את היכולת ליצור בקלות אנימציות כניסה ויציאה, ואנימציות חלקות אל השכבה העליונה וממנה עבור רכיבים שאפשר לסגור, כמו חלונות דו-שיח וחלונות קופצים.
כדי למלא את הפערים האלה, גרסאות Chrome 116 ו-117 כוללות ארבע תכונות חדשות בפלטפורמת האינטרנט, שמאפשרות אנימציות ומעברים חלקים לנכסים נפרדים.
ארבע התכונות החדשות האלה כוללות:
- היכולת ליצור אנימציה של
display
ו-content-visibility
בציר הזמן של נקודות מפתח (החל מגרסה 116 של Chrome). - המאפיין
transition-behavior
עם מילת המפתחallow-discrete
כדי לאפשר מעברים של נכסים נפרדים כמוdisplay
(מ-Chrome 117). - הכלל
@starting-style
להנפשה של אפקטים של כניסה מ-display: none
אל השכבה העליונה (מ-Chrome 117). - המאפיין
overlay
כדי לשלוט בהתנהגות של השכבה העליונה במהלך אנימציה (החל מ-Chrome 117).
הצגת אנימציות בתמונות מפתח
החל מגרסה 116 של Chrome, אפשר להשתמש ב-display
וב-content-visibility
בכללים של פריימים מרכזיים. לאחר מכן, הם יוחלפו בזמן שמופיע פריים המפתח. אין צורך בערכים חדשים נוספים כדי לתמוך בכך:
.card {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
100% {
opacity: 0;
display: none;
}
}
בדוגמה הקודמת, האטימות עוברת אנימציה ל-0 במשך 0.5 שניות, ואז מוגדר לה הצגה כ'ללא'. בנוסף, מילת המפתח forwards
מבטיחה שהאנימציה תישאר במצב הסופי שלה, כך שהרכיב שאליו היא חלה יישאר בסטטוסים display: none
ו-opacity: 0
.
זוהי דוגמה פשוטה שממחישה מה אפשר לעשות באמצעות מעבר (ראו הדגמה בקטע בנושא מעברים). עם זאת, לא ניתן ליצור באמצעות מעברים אנימציות מורכבות יותר, כמו בדוגמה הבאה:
.card {
animation: spin-and-delete 1s ease-in forwards;
}
@keyframes spin-and-delete {
0% {
transform: rotateY(0);
filter: hue-rotate(0);
}
80% {
transform: rotateY(360deg);
filter: hue-rotate(180deg);
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
האנימציה spin-and-delete
היא אנימציית יציאה. קודם הכרטיס יתהפך על ציר ה-y, יתבצע בו סיבוב של גוון ואז, ב-80%
בקו הזמן, העכירות שלו תעבור מ-1 ל-0. בסיום, הכרטיס עובר מ-display: block
ל-display: none
.
באנימציות היציאה האלה, במקום להחיל אותן ישירות על רכיב, אפשר להגדיר טריגר לאנימציות. לדוגמה, אפשר לצרף מאזין לאירועים ללחצן שמפעיל מחלקה כדי להחיל את האנימציה, כך:
.spin-out {
animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
document.querySelector('.card').classList.add('spin-out');
})
המצב הסופי של הדוגמה שלמעלה הוא display:none
. יש הרבה מקרים שבהם כדאי להמשיך הלאה ולהסיר את צומת ה-DOM עם זמן קצוב לתפוגה כדי לאפשר לאנימציה להסתיים קודם.
מעבר בין אנימציות נפרדות
בניגוד ליצירת אנימציה של מאפיינים נפרדים באמצעות פריימים מרכזיים, כדי לבצע מעבר בין מאפיינים נפרדים צריך להשתמש במצב התנהגות המעבר allow-discrete
.
הנכס transition-behavior
המצב allow-discrete
מאפשר מעבר דיסקרטי, והוא ערך של המאפיין transition-behavior
. אפשר להזין ב-transition-behavior
שני ערכים: normal
ו-allow-discrete
.
.card {
transition: opacity 0.25s, display 0.25s;
transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}
.card.fade-out {
opacity: 0;
display: none;
}
הערך הזה מוגדר גם בקיצור הדרך transition
, כך שאפשר להשמיט את הנכס ולהשתמש במילת המפתח allow-discrete
בסוף הקיצור הדרך transition
לכל מעבר.
.card {
transition: opacity 0.5s, display 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
אם אתם רוצים להוסיף אנימציה לכמה מאפיינים נפרדים, תצטרכו לכלול את הערך allow-discrete
אחרי כל מאפיין שתרצו להוסיף לו אנימציה. לדוגמה:
.card {
transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
הכלל @starting-style
לאנימציות כניסה
עד עכשיו, המאמר הזה עסק באנימציות יציאה. כדי ליצור אנימציות כניסה, צריך להשתמש בכלל @starting-style
.
משתמשים ב-@starting-style
כדי להחיל סגנון שהדפדפן יכול לחפש לפני שהרכיב נפתח בדף. זהו המצב 'לפני הפתיחה' (המצב שממנו מתחילה האנימציה).
/* 0. IS-OPEN STATE */
/* The state at which the element is open + transition logic */
.item {
height: 3rem;
display: grid;
overflow: hidden;
transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}
/* 1. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 2. EXITING STATE */
/* While it is deleting, before DOM removal in JS, apply this
transformation for height, opacity, and a transform which
skews the element and moves it to the left before setting
it to display: none */
.is-deleting {
opacity: 0;
height: 0;
display: none;
transform: skewX(50deg) translateX(-25vw);
}
עכשיו יש לכם גם מצב כניסה וגם מצב יציאה לפריטים האלה ברשימת המשימות:
אנימציה של רכיבים אל השכבה העליונה וממנה
כדי להציג אנימציה של רכיבים אל השכבה העליונה וממנה, מציינים את @starting-style
במצב 'פתוח' כדי להודיע לדפדפן מאיפה להציג את האנימציה. בתיבת דו-שיח, המצב הפתוח מוגדר באמצעות המאפיין [open]
. כדי ליצור חלון קופץ, משתמשים בפסאודו-כיתה :popover-open
.
דוגמה פשוטה לתיבת דו-שיח עשויה להיראות כך:
/* 0. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 1. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 2. EXIT STATE */
dialog {
transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
translate: 0 100vh;
}
בדוגמה הבאה, ההשפעות של הכניסה והיציאה הן שונות. כדי להיכנס, מפעילים אנימציה מלמטה למעלה בחלון התצוגה, ומסיימים את האפקט בחלק העליון של חלון התצוגה. הוא נכתב גם באמצעות CSS בתצוגת עץ, כדי לאפשר אנקפסולציה חזותית טובה יותר.
כשאתם יוצרים אנימציה של חלון קופץ, צריך להשתמש בפסאודו-סיווג :popover-open
במקום במאפיין open
ששימש בעבר.
.settings-popover {
&:popover-open {
/* 0. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
/* 1. BEFORE-OPEN STATE */
/* Initial state for what we're animating *in* from,
in this case: goes from lower (y + 20px) to center */
@starting-style {
transform: translateY(20px);
opacity: 0;
}
}
/* 2. EXIT STATE */
/* Initial state for what we're animating *out* to ,
in this case: goes from center to (y - 50px) higher */
transform: translateY(-50px);
opacity: 0;
/* Enumerate transitioning properties,
including display and allow-discrete mode */
transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}
מלון אחד (overlay
)
לבסוף, כדי להעביר את popover
או dialog
לשלב הדעיכה בשכבה העליונה, מוסיפים את הנכס overlay
לרשימת המעברים. popover
ו-dialog
גורמים לבריחה (escape) של טרנספורמציות וקליפים של אב קדמון, וגם מעבירים את התוכן לשכבה העליונה. אם לא תבצעו את המעבר overlay
, הרכיב יחזור מיד להיות חתוך, מעוצב ומכוסה, ולא תראו את המעבר מתבצע.
[open] {
transition: opacity 1s, display 1s allow-discrete;
}
במקום זאת, צריך לכלול את overlay
במעבר או באנימציה כדי להנפיש את overlay
יחד עם שאר התכונות, ולוודא שהוא נשאר בשכבה העליונה במהלך ההנפשה. התמונה תהיה חלקה יותר.
[open] {
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
בנוסף, כשיש כמה רכיבים פתוחים בשכבה העליונה, שכבת-העל עוזרת לכם לשלוט במעבר החלק אל השכבה העליונה וממנה. אפשר לראות את ההבדל בדוגמה הפשוטה הזו. אם לא מחילים את overlay
על חלון הקופץ השני בזמן ההעברה שלו החוצה, הוא יזוז קודם מהשכבה העליונה, יקפוץ מאחורי חלון הקופץ השני, ואז יתחיל את המעבר. זהו אפקט לא חלק במיוחד.
הערה לגבי מעברים בין תצוגות
אם אתם מבצעים שינויים ב-DOM, כמו הוספה והסרה של רכיבים מה-DOM, פתרון מצוין נוסף ליצירת אנימציות חלקות הוא מעבר בין תצוגות. ריכזנו כאן שתי דוגמאות מהדוגמאות שלמעלה שנוצרו באמצעות מעברים בין תצוגות.
בדמו הראשון הזה, במקום להגדיר את @starting-style
וטרנספורמציות CSS אחרות, מעברי התצוגה יטפלו במעבר. כך מגדירים את המעבר בין התצוגות:
קודם כול, ב-CSS, נותנים לכל כרטיס view-transition-name
נפרד.
.card-1 {
view-transition-name: card-1;
}
.card-2 {
view-transition-name: card-2;
}
/* etc. */
לאחר מכן, ב-JavaScript, עוטפים את המוטציה של DOM (במקרה הזה, הסרת הכרטיס) במעבר תצוגה.
deleteBtn.addEventListener('click', () => {
// Check for browser support
if (document.startViewTransition) {
document.startViewTransition(() => {
// DOM mutation
card.remove();
});
}
// Alternative if no browser support
else {
card.remove();
}
})
עכשיו הדפדפן יכול לטפל בהיעלמות ובשינוי של כל כרטיס למיקום החדש שלו.
דוגמה נוספת למקרה שבו האפשרות הזו יכולה להיות שימושית היא הדגמה של הוספה/הסרה של פריטים ברשימה. במקרה כזה, חשוב לזכור להוסיף view-transition-name
ייחודי לכל כרטיס שנוצר.
סיכום
התכונות החדשות האלה בפלטפורמה מקריבות אותנו עוד יותר ליצירת אנימציות חלקות של כניסה ויציאה בפלטפורמת האינטרנט. מידע נוסף זמין בקישורים הבאים: