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

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

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

תמיכה בדפדפנים

  • Chrome: 74.
  • Edge: ‏ 79.
  • Firefox: 63.
  • Safari: 10.1.

מקור

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

קבוצה גדולה של אנשים שמחליקים על הקרח.
עומס ויזואלי בחיים האמיתיים.

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

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

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

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

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

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

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

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

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

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

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

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

Media Queries ברמה 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 יופעלו באופן דינמי על ידי הדפדפן כשההעדפות של המשתמש ישתנו, אבל אני צריך להקשיב לשינויים בעצמי כדי להפסיק באופן ידני את האנימציות שעשויות לפעול (או להפעיל אותן מחדש אם המשתמש מאפשר לי):

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 הנכון בקוד, מטעמי ביצועים.

הדגמה (דמו)

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

סרטון של אפליקציית הדגמה של prefers-reduced-motion

מסקנות

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

קבוצת העבודה של 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), לכן חשוב להשבית אותה אם מבחינים בבעיות.

תודות

תודה רבה ל-Stephen McGruer שהטמיע את prefers-reduced-motion ב-Chrome, וביחד עם Rob Dodson גם בדק את המסמך הזה. תמונה ראשית (Hero) של Hannah Cauhepe ב-Unsplash.