העדפה לצמצום תנועה: לפעמים פחות תנועה היא יותר

שאילתת המדיה עם תנועה בצמצום העדפה מזהה אם המשתמש ביקש במערכת ההפעלה כדי לצמצם את כמות האנימציה או התנועה שהיא משתמשת בה.

לא כולם אוהבים אנימציות דקורטיביות או מעברים, וחלק מהמשתמשים חווים תנועה בלי הפסקה מחלה כשמתמודדים עם גלילה פרלקסית, אפקטים של שינוי מרחק התצוגה ועוד. המדיה של העדפת המשתמש שאילתה prefers-reduced-motion מאפשרת לך לעצב וריאציה של האתר בהפחתת תנועה עבור משתמשים מבטאים את ההעדפה הזו.

תמיכה בדפדפן

  • Chrome: 74.
  • קצה: 79.
  • Firefox: 63.
  • Safari: 10.1.

מקור

יותר מדי תנועה במציאות ובאינטרנט

ביום אחר, החלקה על הקרח עם הילדים שלי. היה יום מקסים, השמש זרחה והקרח הזירה הייתה עמוסה באנשים ⛸. הבעיה היחידה עם זה: אני לא מתמודד בצורה טובה עם צפיפות. יחד עם זאת הרבה יעדים נעים, אני לא מצליח להתמקד באף דבר, ובסוף בסופו של דבר יאבד עם הרגשה שלמה עומס יתר ויזואלי, כמעט כמו בוהה בנמל 🐜.

המון כפות רגליים של אנשים שמחליקים על הקרח.
עומס יתר ויזואלי בחיים האמיתיים.

מדי פעם, זה יכול לקרות באינטרנט: עם מודעות מהבהבות, אפקטים מהודרים של פרלקס, הפתעה אפשר לחשוף אנימציות, הפעלה אוטומטית של סרטונים ועוד – האינטרנט יכול להיות משימה מאתגרת מדי... לשמחתנו, שלא כמו בחיים האמיתיים, יש פתרון לכך. שאילתת המדיה של שירות CSS האפליקציה prefers-reduced-motion מאפשרת למפתחים ליצור וריאנט של דף למשתמשים שמעדיפים צמצום התנועה. פעולה זו יכולה לכלול כל דבר, החל מהימנעות מהפעלה אוטומטית של סרטונים ועד השבתה של אפקטים מסוימים בלבד לצורך עיצוב מחדש של הדף למשתמשים מסוימים.

לפני שנתעמק בתכונה, אני רוצה לקחת צעד לאחור ולחשוב על אילו אנימציות משתמשים באינטרנט. אם רוצים, אפשר גם לדלג על פרטי הרקע דלגו ישר לפרטים הטכניים.

אנימציה באינטרנט

לרוב משתמשים באנימציה כדי לתת משוב למשתמש, למשל כדי להודיע לו התקבלה פעולה ונמצאת בעיבוד. לדוגמה, באתר קניות, מוצר להיות מונפש כדי "לטוס" לעגלת קניות וירטואלית, שמוצגת כסמל בפינה השמאלית העליונה באתר.

תרחיש לדוגמה נוסף כולל שימוש בתנועה פריצה לתפיסת המשתמשים באמצעות שילוב של מסכי שלד, מטא-נתונים לפי הקשר ותצוגות מקדימות של תמונות באיכות נמוכה משקיעים הרבה זמן במשתמש ויוצרות את החוויה מהירה יותר. הרעיון הוא לתת הקשר למשתמשים לגבי מה שצפוי, ובינתיים, לטעון דברים מהר ככל האפשר.

לסיום, יש אפקטים דקורטיביים כמו אנימציה הדרגתית, גלילת פרלקס, רקע סרטונים ועוד כמה סרטונים. משתמשים רבים נהנים מהאנימציות האלה, אבל יש משתמשים שלא אוהבים אותן כי שדעתם מוסחת או מאטה. במקרה הגרוע ביותר, המשתמשים עלולים אפילו לסבול מתנועה מחלה, כאילו הייתה חוויה בחיים האמיתיים, לכן למשתמשים האלה צמצום האנימציות הוא טיפול רפואי צורך.

הפרעת ספקטרום וסטיבולרית שמופעלת על ידי תנועה

חוויית השימוש של חלק מהמשתמשים הסחות דעת או בחילה כתוצאה מתוכן אנימציה. לדוגמה, אנימציות גלילה יכולות לגרום להפרעות וסטיבולאריות כשאלמנטים אחרים שקשור לגלילה, זז הרבה. לדוגמה, אנימציות גלילה עם פרלקס עלול לגרום להפרעות וסטיבולריות כי אלמנטים ברקע זזים בקצב שונה מזה של החזית רכיבים. תגובות של הפרעה וסטיבולרית (אוזן פנימית) כוללות סחרחורת, בחילה ומיגרנה כאבי ראש, ולפעמים צריך גם מנוחה במיטה כדי להתאושש.

הסרת תנועה במערכות הפעלה

במערכות הפעלה רבות יש הגדרות נגישות לציון העדפה מופחתת תנועה במשך זמן רב. בצילומי המסך הבאים מוצגת ההעדפה Reduce motion של macOS Mojave, וגם ההעדפה הסרת אנימציות ב-Android Pi. כשההעדפות האלה מסומנות, הן גורמות כך שלא תשתמשו באפקטים דקורטיביים, כמו אנימציות של הפעלת האפליקציה. היישומים עצמם יכולים להשתמש בהגדרה הזו ולהסיר את כל האנימציות המיותרות.

מסך ההגדרות של macOS שמופיע בו הכיתוב 'הפחתת תנועה' מסומנת.
מסך ההגדרות של Android עם האפשרות 'הסרת אנימציות' מסומנת.

הסרת תנועה באינטרנט

שאילתות מדיה ברמה 5 מספקת את התנועה המופחתת העדפות המשתמש גם באינטרנט. שאילתות מדיה מאפשרות למחברים לבדוק ערכים או תכונות ולשלוח שאילתות לגביהם של סוכן המשתמש או של מכשיר התצוגה, ללא קשר למסמך שבו מתבצע עיבוד. שאילתת המדיה נעשה שימוש ב-prefers-reduced-motion כדי לזהות אם המשתמש הגדיר העדפה של מערכת ההפעלה לצמצום כמות האנימציה התנועה שהיא משתמשת בו. יכולים להיות לו שני ערכים אפשריים:

  • no-preference: מציין שלמשתמש לא הייתה העדפה בהפעלה הבסיסית המערכת. הערך של מילת המפתח מוערך כ-false בהקשר הבוליאני.
  • reduce: מציין שהמשתמש הגדיר העדפה של מערכת הפעלה שמציינת על הממשקים לצמצם את התנועה או את האנימציה, עדיף עד לנקודה שבה כל תנועה תוסר.

עבודה עם שאילתת מדיה מהקשרים של CSS ו-JavaScript

כמו בכל שאילתות המדיה, אפשר לבדוק את prefers-reduced-motion מתוך הקשר של CSS הקשר ל-JavaScript.

כדי להמחיש את שניהם, נניח שיש לי לחצן הרשמה חשוב שאני רוצה שהמשתמש ילחץ עליו. אני אפשר להגדיר 'רטט' שמושך את תשומת הלב אבל בתור אזרח אינטרנט טוב אנגן רק למשתמשים שמסכימים במפורש עם אנימציות, אבל לא לכל אחד אחר, שיכול להיות משתמשים שביטלו את הסכמתם להצגת אנימציות, או משתמשים בדפדפנים שלא מבינים את שאילתת המדיה.

/*
  If the user has expressed their preference for
  reduced motion, then don't use animations on buttons.
*/
@media (prefers-reduced-motion: reduce) {
  button {
    animation: none;
  }
}

/*
  If the browser understands the media query and the user
  explicitly hasn't set a preference, then use animations on buttons.
*/
@media (prefers-reduced-motion: no-preference) {
  button {
    /* `vibrate` keyframes are defined elsewhere */
    animation: vibrate 0.3s linear infinite both;
  }
}

כדי להמחיש איך לעבוד עם prefers-reduced-motion עם JavaScript, נניח שיש לי הגדיר אנימציה מורכבת עם Web Animations API. אומנם כללי CSS יופעל באופן דינמי על ידי הדפדפן כשהעדפת המשתמש תשתנה, עבור JavaScript אני רוצה להאזין לשינויים בעצמי, ואז להפסיק באופן ידני את הפעילות הפוטנציאלית אנימציות (או להפעיל אותן מחדש אם המשתמש מאפשר לי):

const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
mediaQuery.addEventListener('change', () => {
  console.log(mediaQuery.media, mediaQuery.matches);
  // Stop JavaScript-based animations.
});

שימו לב שהסוגריים מסביב לשאילתה של המדיה בפועל הם בגדר חובה:

מה אסור לעשות
window.matchMedia('prefers-reduced-motion: reduce');
מה מותר לעשות
window.matchMedia('(prefers-reduced-motion: reduce)');

עבודה עם שאילתת מדיה מהקשרים של <picture>

מקרה לדוגמה: כשרוצים להפעיל קובץ AVIF, WebP או GIF באנימציה תלויה מאפיין media. אם הערך של (prefers-reduced-motion: no-preference) הוא true, אפשר: הצגת הגרסה המונפשת, אחרת הגרסה הסטטית:

<picture>
  <!-- Animated versions. -->
  <source
    srcset="nyancat.avifs"
    type="image/avif"
    media="(prefers-reduced-motion: no-preference)"
  />
  <source
    srcset="nyancat.gif"
    type="image/gif"
    media="(prefers-reduced-motion: no-preference)"
  />
  <!-- Static versions. -->
  <img src="nyancat.png" alt="Nyan cat" width="250" height="250" />
</picture>

אפשר לראות את הדוגמה הבאה. כדי לראות את ההבדלים, מחליפים את העדפות התנועה של המכשיר.

חתול ניאן המפורסם.

לגלות את ההעדפות של המשתמש בזמן הבקשה

כותרת של הרמז ללקוח ב-Sec-CH-Prefers-Reduced-Motion מאפשר לאתרים לקבל את העדפות התנועה של המשתמש באופן אופציונלי בזמן הבקשה, שמאפשרים לשרתים להטביע את ה-CSS הנכון מסיבות של ביצועים.

הדגמה (דמו)

יצרתי הדגמה קטנה שמבוססת על הסרטון המדהים של רוגריו ויצ'נטה 🐈 HTTP סטטוס חתולים. קודם כל, חשבו רגע על הבדיחה, ממש מצחיק, ואני אמתין. עכשיו, אחרי שחזרת, אני רוצה להציג demo. כשגוללים, כל חתול בסטטוס HTTP מופיעה לסירוגין מצד ימין או מצד שמאל. קצב הרינדור של 60 FPS הוא חלק וחלק אבל כפי שתואר קודם, יכול להיות שחלק מהמשתמשים לא יאהבו אותה או אפילו יחלו בה תנועה, כך ההדגמה מתוכנתת להתייחס אל prefers-reduced-motion. זה אפילו עובד באופן דינמי, כדי שמשתמשים לשנות את ההעדפה שלהם תוך כדי תנועה, ללא צורך בטעינה מחדש. אם המשתמש מעדיף תנועה מופחתת, אנימציית החשיפה המיותרת נעלמת, ורק תנועת הגלילה הרגילה נשארת. בהקלטת המסך הבאה מוצגת ההדגמה בפעולה:

סרטון של הדגמה של prefers-reduced-motion יישום

מסקנות

חשוב לכבד את העדפות המשתמשים באתרים מודרניים, והדפדפנים חושפים יותר ויותר שמאפשרות למפתחי אתרים לעשות זאת. דוגמה נוספת שהושקה היא prefers-color-scheme, מזהה אם המשתמש מעדיפים ערכת צבעים בהירה או כהה. אפשר לקרוא את כל המידע על prefers-color-scheme במאמר שלי שלום אפל, חבר ותיק 🌒.

בקבוצת העבודה של שירות ה-CSS אנחנו מיישמים סטנדרטיזציה רבה יותר שאילתות מדיה להעדפות משתמשים כמו prefers-reduced-transparency (זיהוי אם המשתמש מעדיפים שקיפות מופחתת) prefers-contrast (זיהוי אם המשתמש ביקש מהמערכת להגדיל או להפחית את מידת הניגודיות בין צבעים קרובים), ו-inverted-colors (מזהה אם המשתמש העדפה של צבעים הפוכים).

(בונוס) אילוץ צמצום התנועה בכל האתרים

לא כל אתר ישתמש ב-prefers-reduced-motion, או אולי לא בצורה משמעותית מספיק לטעם שלך. אם אתם רוצים להפסיק את התנועה בכל האתרים מסיבה כלשהי, אתם יכולים לעשות זאת. אחת הדרכים מצב זה הוא להחדיר גיליון סגנונות עם ה-CSS הבא לכל דף אינטרנט שבו אתם מבקרים. יש יש כמה תוספים לדפדפן שמאפשרות זאת.

@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    animation-delay: -1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    background-attachment: initial !important;
    scroll-behavior: auto !important;
    transition-duration: 1ms !important;
    transition-delay: -1ms !important;
  }
}

הדרך הזו פועלת היא ששירות ה-CSS הקודם מבטל את משכי הזמן של כל האנימציות והמעברים. לפרק זמן קצר כל כך עד שכבר לא ניתן להבחין בהם. כי חלק מהאתרים תלויים באנימציה כדי שיפעל כראוי (ייתכן ששלב מסוים תלוי בהפעלה של אירוע אחד (animationend)), הגישה הקיצונית יותר של animation: none !important; לא תעבוד. אפילו שהפריצה הקודמת לא להצליח בכל האתרים (לדוגמה, היא לא יכולה להפסיק תנועה שהחלה באמצעות Web Animations API), לכן חשוב להשבית אותו כשמבחינים בתקלה.

אישורים

תודה רבה לסטיבן מקגרואר שהטמיע prefers-reduced-motion ב-Chrome וביחד עם גם רוב דודסון – בדק את המסמך הזה. תמונה ראשית (Hero) מאת חנה קאוהפה (Hanah Cauhepe) ב-Unbounce.