एक्सेसिबल एनिमेशन: Reduced Motion और WCAG
Charmotion टीम द्वारा · अपडेट:

एक्सेसिबल एनिमेशन यूज़र की Reduce Motion सेटिंग का सम्मान करता है और उसे रोका जा सकता है। Web पर prefers-reduced-motion: reduce या SwiftUI में accessibilityReduceMotion चेक करें और लूपिंग मोशन की जगह स्थिर पोज़ दिखाएँ। WCAG 2.2 SC 2.2.2 के तहत, दूसरे कंटेंट के साथ पाँच सेकंड से ज़्यादा चलने वाले अपने-आप शुरू होने वाले मोशन के लिए pause, stop या hide कंट्रोल ज़रूरी है।
मुख्य बातें
prefers-reduced-motionकी दो वैल्यू हैं,no-preferenceऔरreduce, और यह सभी आधुनिक ब्राउज़र में सपोर्टेड है।- जब यह
reduceहो, तो कैरेक्टर लूप की जगह स्थिर पोज़ या छोटा सा फ़ेड दिखाएँ। - WCAG 2.2.2 (Level A): पाँच सेकंड से लंबे ऑटोप्ले मोशन को रोकने, बंद करने या छिपाने का तरीका होना चाहिए।
- जब इंतज़ार के दौरान कोई इंटरैक्शन संभव न हो, तो loading एनिमेशन को ज़रूरी (essential) माना जा सकता है।
- एक सेकंड में तीन बार से ज़्यादा कभी फ़्लैश न करें (SC 2.3.1, Level A)।
prefers-reduced-motion क्या है?
prefers-reduced-motion एक CSS media feature है जो पेज को बताता है कि यूज़र ने अपने ऑपरेटिंग सिस्टम में गैर-ज़रूरी मोशन कम करने को कहा है या नहीं। इसकी दो वैल्यू हैं: no-preference और reduce। MDN के अनुसार यह जनवरी 2020 से सभी ब्राउज़र में उपलब्ध है।
यूज़र इसे ब्राउज़र में सेट नहीं करते। वे इसे OS में सेट करते हैं, और ब्राउज़र इसे आगे पहुँचा देता है:
- iOS और iPadOS: Settings > Accessibility > Motion > Reduce Motion।
- macOS: System Settings > Accessibility > Display > Reduce motion।
- Windows 11: Settings > Accessibility > Visual effects > Animation effects (off)।
- Android 9+: Settings > Accessibility > Remove animations।
लोग इसे अलग-अलग कारणों से चालू करते हैं। वेस्टिबुलर डिसऑर्डर में बड़ी हलचल, पैरालैक्स और ज़ूम से चक्कर या मतली हो सकती है। कुछ लोगों को पढ़ते समय लगातार चलता मोशन ध्यान भटकाने वाला लगता है। "Reduce" का मतलब "बिल्कुल नहीं" होना ज़रूरी नहीं। हल्का opacity फ़ेड या रंग बदलना आमतौर पर ठीक है। जो हटना चाहिए, वह है बड़ी दूरी तक हलचल, घूमना, उछलना और कभी न रुकने वाला लूपिंग मोशन।
CSS और JavaScript में reduced motion (मोशन कम करें) को कैसे सपोर्ट करें?
CSS में, डिफ़ॉल्ट रूप से पूरा एनिमेशन लिखें और media query के अंदर उसे बंद करें। ज़्यादा सुरक्षित विकल्प यह है कि एनिमेशन को @media (prefers-reduced-motion: no-preference) में रखें, ताकि मोशन तभी जुड़े जब यूज़र की कोई पसंद तय न हो। पहला पैटर्न ऐसा दिखता है:
.mascot { animation: bob 3s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
.mascot { animation: none; }
}
JavaScript में matchMedia इस्तेमाल करें। बदलावों को भी सुनें, क्योंकि पेज खुले रहने के दौरान यूज़र सेटिंग बदल सकता है:
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
function applyMotionPreference() {
document.documentElement.classList.toggle("reduce-motion", query.matches);
}
applyMotionPreference();
query.addEventListener("change", applyMotionPreference);
React में इसे एक छोटे hook में रखें जो query.matches लौटाए और बदलाव पर फिर से रेंडर करे, फिर जहाँ भी आप एनिमेशन शुरू करते हैं, वहाँ इसी के आधार पर फ़ैसला करें।
वीडियो लूप के लिए, चलाने से पहले पसंद चेक करें। अगर यह reduce है, तो <video> को उसके poster फ़्रेम पर रुका रहने दें, या वीडियो की जगह poster इमेज रेंडर करें।
Rive या वीडियो लूप की जगह स्थिर पोज़ कैसे दिखाएँ?
सबसे आसान पैटर्न जो हर फ़ॉर्मेट के साथ काम करता है: कैरेक्टर के न्यूट्रल पोज़ की एक स्थिर इमेज रखें और मोशन कम करें सेटिंग चालू होने पर एनिमेशन की जगह उसे रेंडर करें।
वीडियो के लिए यह स्थिर इमेज poster फ़्रेम होती है। idle लूप के पहले फ़्रेम को ट्रांसपेरेंट PNG या WebP के रूप में एक्सपोर्ट करें, ताकि reduced-motion वर्ज़न बिल्कुल वैसा ही दिखे, बस हिले नहीं।
Rive कैरेक्टर के लिए आपके पास दो विकल्प हैं:
- स्थिर इमेज रेंडर करें, यानी Rive कैनवस माउंट करने की जगह idle पोज़ की इमेज दिखाएँ। इससे रनटाइम लोड करना भी बच जाता है, जिससे इन यूज़र्स का बैंडविड्थ बचता है।
- Rive रखें, लेकिन एक शांत स्टेट पर टिके रहें। स्टेट मशीन को उसके सबसे शांत लूप पर सेट करें और उछलने या खिसकने वाले वन-शॉट रिएक्शन (एक बार चलने वाले रिएक्शन) छोड़ दें। Rive स्टेट मशीन "settle" हो सकती हैं, यानी जब कुछ नहीं बदलता तो रनटाइम आगे बढ़ना बंद कर देता है।
अगर आप Charmotion फ़ाइल इस्तेमाल करते हैं, तो idle (mood 0) और sleeping (mood 8) लूप टिके रहने के लिए सबसे शांत स्टेट हैं। आप कोई भी तरीका चुनें, मोशन जो जानकारी देता था वह फिर भी दें। अगर कोई success एनिमेशन यूज़र को बताता है कि पेमेंट हो गया, तो यह बताने वाला टेक्स्ट या आइकन बनाए रखें।
iOS पर Reduce Motion को कैसे सपोर्ट करें?
SwiftUI यूज़र की सेटिंग को environment value accessibilityReduceMotion के ज़रिए देता है। इसे किसी भी view में पढ़ें और जब यह true हो, तो स्टैटिक ब्रांच चुनें:
struct MascotView: View {
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
if reduceMotion {
Image("mascot-idle-still")
.resizable()
.scaledToFit()
} else {
AnimatedMascot() // your Rive view or video player
}
}
}
यह value लाइव अपडेट होती है, इसलिए अगर आपका ऐप चलते समय यूज़र Settings बदलता है, तो view अपने आप बदल जाता है। जो ट्रांज़िशन आप खुद जोड़ते हैं, उन पर भी यही नियम लागू करें: slide या spring की जगह cross-fade इस्तेमाल करें, या कोई एनिमेशन न रखें।
वेब पर iOS का Safari यही सेटिंग prefers-reduced-motion के ज़रिए बताता है, इसलिए OS का एक ही स्विच आपके ऐप और आपकी वेबसाइट दोनों पर लागू होता है।
क्या मेरे लूपिंग मैस्कॉट के लिए pause बटन ज़रूरी है?
अक्सर, हाँ। WCAG 2.2 का Success Criterion 2.2.2 Pause, Stop, Hide, Level A का है, यानी वह बुनियादी स्तर जिसकी ज़्यादातर एक्सेसिबिलिटी पॉलिसी माँग करती हैं। यह उस हिलते, ब्लिंक होते या स्क्रॉल होते कंटेंट पर लागू होता है जो ये तीनों शर्तें पूरी करता है:
- यह अपने आप शुरू होता है।
- यह पाँच सेकंड से ज़्यादा चलता है।
- यह दूसरे कंटेंट के साथ-साथ दिखाया जाता है।
अगर तीनों शर्तें सही हैं, तो यूज़र के पास इसे pause, stop या hide करने का तरीका होना चाहिए, जब तक कि मोशन ज़रूरी न हो। आपके पेज के टेक्स्ट के पास लगातार लूप होता idle मैस्कॉट तीनों शर्तें पूरी करता है।
नियम का पालन करने के तरीके:
- अपने आप रुक जाए। लूप को कुछ बार चलाएँ, कुल मिलाकर पाँच सेकंड से कम, फिर एक स्थिर फ़्रेम पर रोक दें।
- दिखने वाला कंट्रोल जोड़ें। एनिमेशन के पास एक pause बटन, जो
video.pause()कॉल करे या Rive canvas की जगह स्थिर इमेज दिखा दे। - यूज़र को इसे छिपाने दें। एक dismiss कंट्रोल मोशन को पूरी तरह हटा देता है।
prefers-reduced-motion का सम्मान करना अच्छी प्रैक्टिस है, लेकिन अकेले इससे 2.2.2 पूरा नहीं होता। मोशन से परेशान होने वाले कई लोगों को वह OS सेटिंग कभी मिली ही नहीं।
क्या loading एनिमेशन को छूट मिलती है?
मिल सकती है। SC 2.2.2 के लिए W3C के Understanding डॉक्यूमेंट के अनुसार, preload चरण के दौरान चलने वाला एनिमेशन "ज़रूरी माना जा सकता है, अगर उस चरण में किसी भी यूज़र के लिए इंटरैक्शन संभव न हो।" तर्क यह है: प्रगति का इकलौता संकेत छिपाने से यूज़र को लग सकता है कि ऐप अटक गया है।
यह छूट सीमित है। यह फ़ुल-स्क्रीन loader या ब्लॉक करने वाले इंतज़ार पर लागू होती है। यह उस मैस्कॉट पर लागू नहीं होती जो कोने में loading या thinking लूप चलाता रहता है, जबकि यूज़र पढ़ और टाइप कर सकता है। ऐसे में या तो लूप को हल्का रखें और काम खत्म होते ही रोक दें, या pause का विकल्प दें।
loading लूप को असली काम से जोड़ें। request शुरू होते ही लूप शुरू करें, और उसके पूरा होने पर उसे success या error के वन-शॉट रिएक्शन (एक बार चलने वाला रिएक्शन) से खत्म करें। काम खत्म होने के बाद भी चलता लूप एक्सेसिबिलिटी की समस्या भी है और गलत स्टेटस संकेत भी। इंतज़ार के समय से जुड़ी गाइडेंस के लिए Animation Durations & Loading UX देखें।
इंटरैक्शन एनिमेशन और flashing का क्या?
कैरेक्टर एनिमेशन पर दो और मानदंड (criteria) लागू होते हैं।
SC 2.3.3 Animation from Interactions (Level AAA)
"इंटरैक्शन से ट्रिगर होने वाले मोशन एनिमेशन को बंद किया जा सके, जब तक कि एनिमेशन ज़रूरी न हो।" इसमें ऐसी चीज़ें आती हैं जैसे बटन टैप करने पर उछलने वाला मैस्कॉट या स्क्रीन पर उड़ता हुआ कार्ड। Level AAA शायद ही कभी अनिवार्य होता है, लेकिन इन रिएक्शन के लिए prefers-reduced-motion का सम्मान करके आप इसे कम मेहनत में पूरा कर सकते हैं। फ़ीडबैक बनाए रखें, बस हिलने-डुलने की जगह fade, रंग बदलना या स्थिर इमेज इस्तेमाल करें।
SC 2.3.1 Three Flashes or Below Threshold (Level A)
कंटेंट किसी भी एक सेकंड में तीन बार से ज़्यादा flash नहीं होना चाहिए, जब तक कि वह general और red flash thresholds से नीचे न रहे। तेज़ flashing से photosensitive epilepsy वाले लोगों को दौरे पड़ सकते हैं। error और attention एनिमेशन में इस पर ध्यान दें: लाल ब्लिंक या चमकता strobe ठीक वहीं घुस आता है। ब्लिंक धीमे और हल्के रखें।
प्रोडक्ट UI में मैस्कॉट को शायद ही कभी flash करने की ज़रूरत होती है। इसकी जगह एक pulse या साफ़ मैसेज से ज़रूरी बात बताएँ।
लूपिंग कैरेक्टर एनिमेशन को एक्सेसिबल कैसे बनाएँ
- एक स्थिर पोज़ तैयार करें. कैरेक्टर के न्यूट्रल या idle फ़्रेम का ट्रांसपेरेंट PNG या WebP एक्सपोर्ट करें।
- यूज़र की पसंद पहचानें. वेब पर
matchMedia("(prefers-reduced-motion: reduce)")या SwiftUI मेंaccessibilityReduceMotionइस्तेमाल करें, और बदलावों पर नज़र रखें। - मोशन की जगह स्थिर इमेज दिखाएँ. जब मोशन कम करें सेटिंग चालू हो, तो Rive canvas या वीडियो की जगह स्थिर इमेज रेंडर करें, या बिना वन-शॉट रिएक्शन के एक शांत स्टेट पर रुके रहें।
- pause कंट्रोल जोड़ें. जो लूप अपने आप शुरू होते हैं और दूसरे कंटेंट के साथ पाँच सेकंड से ज़्यादा चलते हैं, उनके लिए दिखने वाला pause, stop या hide बटन जोड़ें (WCAG 2.2.2)।
- loading लूप को सीमित रखें. loading लूप काम शुरू होने पर शुरू करें और काम पूरा होने पर success या error रिएक्शन से खत्म करें।
- flashing की जाँच करें. पक्का करें कि कुछ भी एक सेकंड में तीन बार से ज़्यादा flash न हो, खासकर error और attention स्टेट।
अक्सर पूछे जाने वाले सवाल
क्या prefers-reduced-motion का मतलब है कि मुझे सारे एनिमेशन हटा देने चाहिए?
नहीं। बड़ी हलचल, parallax, घूमना, उछलना और कभी न खत्म होने वाले लूप कम करें। हल्के opacity fade, रंग बदलना और कैरेक्टर का स्थिर पोज़ आमतौर पर ठीक हैं। मोशन जो जानकारी देता था, जैसे success या error स्टेट, उसे टेक्स्ट, आइकन या स्थिर इमेज से बनाए रखें।
क्या WCAG के लिए prefers-reduced-motion का सम्मान करना काफ़ी है?
अकेले नहीं। SC 2.3.3 (AAA) पूरा करने का यह आम तरीका है, लेकिन SC 2.2.2 (Level A) के तहत दूसरे कंटेंट के साथ दिखने वाले, पाँच सेकंड से लंबे ऑटोप्ले मोशन के लिए pause, stop या hide का तरीका फिर भी ज़रूरी है, क्योंकि कई यूज़र OS सेटिंग कभी नहीं बदलते।
मोशन कम करें सेटिंग को टेस्ट कैसे करें?
iOS या macOS की accessibility settings में Reduce Motion चालू करें, Windows 11 में Animation effects बंद करें, या Android पर Remove animations चालू करें। Chrome DevTools में Rendering panel से भी आप यह media feature emulate कर सकते हैं। फिर पुष्टि करें कि लूप रुक जाते हैं और स्थिर पोज़ दिखता है।
इस गाइड से झटपट जवाब
स्रोत
- prefers-reduced-motion, MDN Web Docs
- accessibilityReduceMotion, Apple Developer Documentation
- Understanding SC 2.2.2: Pause, Stop, Hide, W3C WAI
- Understanding SC 2.3.3: Animation from Interactions, W3C WAI
- Understanding SC 2.3.1: Three Flashes or Below Threshold, W3C WAI
- State machines (web runtime), Rive