- אפשר להשתמש ב-
clip-pathוב-mask-imageכדי ליצור חשיפות גיאומטריות בהתאמה אישית ודעיכות חלקות. - כדאי להשתמש באנימציות מבוססות-גלילה (
animation-timeline: scroll()) לאפקטים לא חיוניים שקשורים לגלילה, במקום במאזינים של JS. - אפשר להשתמש במעברי תצוגה כדי ליצור אנימציה בין מצבי פריסה מורכבים בצורה חלקה.
ביצועים
- כדאי להנפיש את
opacityו-transform(כולל מאפייני טרנספורמציה ספציפיים, למשלtranslateבמקוםleft/right/top/bottom) כדי לוודא שהאנימציות יישארו ב-compositor thread. - משתמשים ב-
transition-behavior: allow-discrete, ב-@starting-styleוב-overlay(לרכיבים בשכבה העליונה כמו<dialog>או[popover]) כדי ליצור אנימציה של מצבי כניסה ויציאה נפרדים באופן מקורי. מידע נוסף זמין במאמרים יצירת אנימציה של כניסה ויציאה של רכיבים ויצירת אנימציה של רכיבים אל השכבה העליונה וממנה.
.popover-reveal {
/* Transition discrete display and top-layer overlay alongside opacity */
transition:
opacity ease-out,
display,
overlay;
transition-duration: 0.2s;
transition-behavior: allow-discrete;
}
נגישות
משתמשים בשאילתות מדיה של prefers-reduced-motion כדי להשבית תנועה כבדה למשתמשים שמעדיפים זאת.
- לספק מנגנון השהיה: מאפשרים למשתמשים לעצור קרוסלות, באנרים או אנימציות קבועות אחרות שפועלות באופן אוטומטי.
- ברירת מחדל של תצוגות סטטיות: כדאי להגדיר מצבים סטטיים כברירת מחדל ולאפשר למשתמשים להפעיל תנועה.
- אל תחרגו ממגבלות ההבהוב (שלוש פעמים בשנייה): אל תכללו הבהוב מהיר של אור וחושך. אפקטים כאלה עלולים לגרום להתקפים.
אל תפעילו את animation-duration: 0.01ms; באופן גלובלי, כי זה עלול לגרום לאנימציות מסוימות להיראות יותר צורמות.
במקום זאת, צריך לטפל בהעדפות התנועה בכל מקרה לגופו באמצעות אחת משתי הגישות, ולהטמיע את השאילתה @media בתוך הכלל כדי ששתי הגרסאות יישמרו יחד:
- מתחילים עם אנימציות שמופעלות כברירת מחדל, ומפחיתים אותן באמצעות
@media (prefers-reduced-motion: reduce):
/* Good: Dampen spin states or slow down animations for reduced motion */
.spinner {
animation: spin 1s linear infinite;
@media (prefers-reduced-motion: reduce) {
animation: none;
opacity: 0.5;
}
}
progress:not([value]) {
animation: slide 1s infinite linear;
@media (prefers-reduced-motion: reduce) {
animation-duration: 20s;
}
}
- כדי להתחיל בלי אנימציות כברירת מחדל, ולהפעיל אותן באמצעות
@media (prefers-reduced-motion: no-preference):
/* Good: Default to static or gentle states and opt-in to full motion */
.spinner {
opacity: 0.5;
@media (prefers-reduced-motion: no-preference) {
opacity: 1;
animation: spin 1s linear infinite;
}
}
progress:not([value]) {
animation: slide 20s infinite linear;
@media (prefers-reduced-motion: no-preference) {
animation-duration: 1s;
}
}
עבודה עם אירועי אנימציה ומעבר ב-JavaScript
גם בממשק AnimationEvent (animationstart, animationiteration, animationend, animationcancel) וגם בממשק TransitionEvent (transitionrun, transitionstart, transitionend, transitioncancel), event.target מספק את רכיב ה-DOM המקורי. כדי לגשת לאובייקט Animation הספציפי (Animation, CSSAnimation או CSSTransition) שהפעיל את האירוע, משתמשים במאפיין event.animation לקריאה בלבד.
אם event.animation לא זמין, בדרך כלל אפשר למצוא את המופע של Animation על ידי קריאה ל-event.target.getAnimations() וסינון לפי event.animationName (או event.propertyName למעברים). עם זאת, עדיף להשתמש ישירות ב-event.animation כדי להימנע מכמה תרחישים שבהם ברירת המחדל הזו שמסננת את event.target.getAnimations() לא פועלת כצפוי:
- לאנימציות של Web Animations API (
element.animate()) איןanimationName, ולכן אי אפשר להתאים אותן לפי שם כשמסננים אתevent.target.getAnimations(). - סינון לפי
animationNameעבורAnimationEvents הוא לא חד-משמעי כשיש כמה אנימציות עם אותו שם שמצורפות לאותו רכיב.- שימו לב שהסינון לפי
transitionPropertyעבורTransitionEventפועל כי יש רק אירוע אחד לכל מאפיין מעבר.
- שימו לב שהסינון לפי
- המאפיין
event.targetתמיד מצביע על רכיב ה-DOM המקורי, כך שהוא לא מבחין בין אנימציות שפועלות על הרכיב עצמו לבין אחד מרכיבי הפסאודו שלו, ואילוevent.animation.effect.pseudoElementחושף את רכיב הפסאודו של היעד ישירות.
// Works in most basic CSS animation cases, but fails for WAAPI animations,
// duplicate animation names on the same element, or pseudo-elements.
document.addEventListener('animationstart', (event) => {
const animation = event.target
.getAnimations()
.find((anim) => anim.animationName === event.animationName);
console.log(animation);
});
// PREFERRED: Directly access the exact Animation object via event.animation
document.addEventListener('animationstart', (event) => {
const animation = event.animation;
console.log(animation);
});
אפשר לזהות תמיכה בתכונות באמצעות 'animation' in AnimationEvent.prototype (או 'animation' in TransitionEvent.prototype).