Reduce Motion — تابع accessibility سیستمعاملها و مرورگرها که انیمیشن رابط را برای جلوگیری از ناراحتی کاربران مبتلا به اختلالات دهلیزی غیرفعال یا کاهش میدهد. در iOS این تنظیم در Settings > Accessibility > Motion > Reduce Motion قرار دارد و پارالاکس، انیمیشن انتقال بین صفحهها و افکتهای آیکون را غیرفعال میکند. در Android گزینه مشابه «حذف انیمیشن» در تنظیمات > دسترسپذیری قرار دارد. طبق دادههای W3C WCAG 2.2، انیمیشن بیش از حد میتواند در ۱۵–۳۵٪ افراد مبتلا به اختلالات دهلیزی باعث تهوع، سرگیجه و میگرن شود.
نکات اصلی
Reduce Motion — یک تنظیم سیستمی است که به سیستمعامل، مرورگر و برنامهها دستور میدهد انیمیشن، حرکت، بزرگنمایی و افکتهای پارالاکس را به حداقل برسانند یا کاملاً غیرفعال کنند. این تابع برای افراد مبتلا به اختلالات دهلیزی طراحی شده است که عناصر متحرک رابط در آنها باعث تهوع، سرگیجه، سرگشتگی و میگرن میشود.
سیستم دهلیزی گوش داخلی مسئول حس تعادل و جهتیابی در فضا است. وقتی چشمها حرکت روی صفحه را میبینند اما دستگاه دهلیزی حرکت متناسب بدن را حس نمیکند، تعارض حسی ایجاد میشود. این تعارض واکنش خودمختار را تحریک میکند: تهوع، عرق سرد، سرگیجه. طبق دادههای انجمن اختلالات دهلیزی، حدود ۳۵٪ افراد بالای ۴۰ سال از افکتهای حرکتی در رابطها ناراحت میشوند.
تفاوت کلیدی Reduce Motion با غیرفعالسازی ساده انیمیشن — سطح سیستمی است. تنظیم فعال شده از طریق API سیستمعامل یا تابع رسانهای prefers-reduced-motion CSS به همه برنامهها و وبسایتها منتقل میشود. توسعهدهنده نیازی به حدس زدن ندارد که کاربر انیمیشن میخواهد یا نه — سیستم این را اعلام میکند. این بخشی از رویکرد progressive enhancement است: انیمیشن یک بهبود است، نه یک عنصر اجباری.
Reduce Motion روی افکتهای پارالاکس (جابجایی پسزمینه هنگام کج کردن دستگاه)، انیمیشن انتقال بین صفحهها (push، slide، fade)، بزرگنمایی آیکونها هنگام کلیک، افکتهای پیام (حبابهای SMS)، انیمیشن بارگذاری (spinner، skeleton، progress bar animation)، پارالاکس در بازیها و افکتهای parallax scrolling وب تأثیر میگذارد. تصاویر ثابت و ویدئو تحت تأثیر قرار نمیگیرند.
| نوع انیمیشن | iOS Reduce Motion | Android Remove Animation | CSS prefers-reduced-motion |
|---|---|---|---|
| پارالاکس کاغذدیوار | غیرفعال میکند | غیرفعال میکند | ندارد |
| انتقال بین صفحهها | جایگزین با fade | غیرفعال میکند | CSS transitions |
| انیمیشن آیکونها | غیرفعال میکند | تأثیر ندارد | CSS animations |
| Spinner بارگذاری | تأثیر ندارد | غیرفعال میکند | CSS animations |
| صفحههای Skeleton | تأثیر ندارد | جایگزین با static | CSS animations |
مخاطب اصلی Reduce Motion — افراد مبتلا به اختلالات دهلیزی (بیماری منییر، لابیرنتیت، BPPV)، میگرن (بهویژه با اورا)، کینتوز (بیماری حرکت در حمل و نقل) و برخی اشکال صرع هستند. این تابع همچنین برای کاربران مسن مفید است — تغییرات وابسته به سن در دستگاه دهلیزی حساسیت به حرکت را افزایش میدهد، و برای کاربران مبتلا به ADHD — عناصر متحرک از خواندن منحرف میکنند.
در iOS Reduce Motion در Settings > Accessibility > Motion قرار دارد و شامل سه گزینه است: Reduce Motion (سوئیچ اصلی)، Auto-Play Message Effects (پخش خودکار افکتهای iMessage) و Auto-Play Video Previews (پیشنمایش خودکار ویدئو در App Store). Reduce Motion قدرتمندترین است: پارالاکس کاغذدیوار، انیمیشن باز شدن برنامهها (zoom)، انتقال بین صفحهها (push با cross-fade جایگزین میشود) و افکتهای آیکون در صفحه اصلی را غیرفعال میکند.
از نظر فنی iOS Reduce Motion را در سطح UIKit از طریق UIView animations و UIViewControllerAnimatedTransitioning پیادهسازی میکند. با فعال بودن تنظیم، UIView.animate با مدت > ۰ به ۰.۰۱ ثانیه کاهش مییابد و UIViewController.transitionDuration صفر برمیگرداند. برای پارالاکس، iOS UIInterpolatingMotionEffect را روی UIWindow غیرفعال میکند. توسعهدهنده میتواند وضعیت را از طریق UIAccessibility.isReduceMotionEnabled بررسی کند.
توسعهدهنده میتواند انیمیشن را در iOS با Reduce Motion تطبیق دهد: انتقالهای پیچیده را با افکتهای fade جایگزین کند، پارالاکس را در کامپوننتهای سفارشی UI غیرفعال کند و مدت انیمیشنها را کوتاه کند. SwiftUI یک modifier ویژه .animation(nil) را برای reduceMotion فعال ارائه میدهد.
import UIKit
class MotionManager {
// بررسی وضعیت Reduce Motion
static var isReduceMotionEnabled: Bool {
return UIAccessibility.isReduceMotionEnabled
}
// انیمیشن ایمن با در نظر گرفتن Reduce Motion
static func animate(
duration: TimeInterval,
delay: TimeInterval = 0,
options: UIView.AnimationOptions = [],
animations: @escaping () -> Void,
completion: ((Bool) -> Void)? = nil
) {
let adjustedDuration = isReduceMotionEnabled
? 0.01
: max(duration, 0.01)
UIView.animate(
withDuration: adjustedDuration,
delay: delay,
options: options,
animations: animations,
completion: completion
)
}
}
// SwiftUI — modifier برای Reduce Motion
import SwiftUI
struct MotionAwareView: View {
@Environment(\.accessibilityReduceMotion)
private var reduceMotion
@State private var isAnimating = false
var body: some View {
Circle()
.scaleEffect(isAnimating ? 1.2 : 1.0)
.animation(
reduceMotion
? nil
: .easeInOut(duration: 1.0).repeatForever(),
value: isAnimating
)
.onAppear { isAnimating = true }
}
}
// اشتراک در تغییر Reduce Motion
NotificationCenter.default.addObserver(
self,
selector: #selector(motionStatusChanged),
name: UIAccessibility.reduceMotionStatusDidChangeNotification,
object: nil
)کلاس MotionManager isReduceMotionEnabled را بررسی میکند و مدت انیمیشن را تطبیق میدهد: با Reduce Motion فعال، مدت به ۰.۰۱ ثانیه (عملاً فوری) کاهش مییابد. modifier .animation(nil) SwiftUI انیمیشن را در reduceMotion == true کاملاً غیرفعال میکند. اشتراک در reduceMotionStatusDidChangeNotification امکان تغییر پویای انیمیشن بدون بارگذاری مجدد برنامه را فراهم میکند.
گزینه جداگانه iOS — Auto-Play Message Effects — پخش افکتها در iMessage را کنترل میکند: انیمیشن بالون، کانفتی، لیزرها و آتشبازی. با فعال بودن Reduce Motion، افکتهای iMessage به طور خودکار غیرفعال میشوند. توسعهدهنده میتواند این گزینه را از طریق UIAccessibility.isReduceMotionEnabled بررسی کند — API جداگانهای برای Message Effects وجود ندارد، آنها به تنظیم عمومی متصل هستند.
در Android تنظیم «حذف انیمیشن» در دو مکان قرار دارد: تنظیمات > دسترسپذیری > حذف انیمیشن (برای تنظیمات accessibility) و گزینههای توسعهدهنده > مقیاس انیمیشن (برای توسعهدهندگان). نسخه accessibility همه انیمیشنهای سیستمی از جمله انتقال بین صفحهها، انیمیشن باز شدن برنامهها و افکتهای بارگذاری را غیرفعال میکند. گزینههای توسعهدهنده امکان کاهش مقیاس به ۰.۵x، ۰.۱x یا غیرفعال کردن کامل را میدهند.
از نظر فنی Android غیرفعالسازی انیمیشن را از طریق ویژگیهای سیستمی پیادهسازی میکند: window_animation_scale، transition_animation_scale و animator_duration_scale. با تنظیم accessibility، هر سه مقدار ۰ میگیرند. Launcher سیستم و برنامههای سیستمی این مقادیر را بررسی میکنند. برای برنامههای شخص ثالث، Android استفاده از Jetpack Compose و View system را توصیه میکند که به طور خودکار تنظیم سیستم را از طریق AnimationScaleObserver میخوانند.
توسعهدهنده میتواند وضعیت انیمیشن را در Android از طریق Settings.Global بررسی کرده و UI را تطبیق دهد. Jetpack Compose AnimationScaleObserver را برای تطبیق خودکار ارائه میدهد. مقدار کلیدی — animator_duration_scale: اگر ۰ باشد، انیمیشن کاملاً غیرفعال است.
import android.content.Context
import android.provider.Settings
import android.database.ContentObserver
import android.os.Handler
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.runtime.getValue
class AndroidMotionHelper {
// بررسی غیرفعالسازی انیمیشن
fun isAnimationDisabled(context: Context): Boolean {
return try {
Settings.Global.getFloat(
context.contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE
) == 0f
} catch (e: Settings.SettingNotFoundException) {
false
}
}
// نظارت بر تغییر انیمیشن (ContentObserver)
fun observeAnimationScale(
context: Context,
onChange: (Boolean) -> Unit
): ContentObserver {
val observer = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
onChange(isAnimationDisabled(context))
}
}
context.contentResolver.registerContentObserver(
Settings.Global.getUriFor(
Settings.Global.ANIMATOR_DURATION_SCALE
),
false,
observer
)
return observer
}
}
// Jetpack Compose — انیمیشن با در نظر گرفتن تنظیمات
@Composable
fun MotionAwareAnimation(enabled: Boolean) {
val context = androidx.compose.ui.platform.LocalContext.current
val noMotion = AndroidMotionHelper().isAnimationDisabled(context)
val scale by animateFloatAsState(
targetValue = if (enabled) 1f else 0f,
animationSpec = if (noMotion) {
androidx.compose.animation.core.tween(durationMillis = 0)
} else {
androidx.compose.animation.core.spring()
},
label = "scale"
)
// UI با انیمیشن
}
کلاس AndroidMotionHelper ANIMATOR_DURATION_SCALE را از طریق Settings.Global بررسی میکند، ContentObserver را برای پیگیری تغییرات ارائه میدهد و به انیمیشنهای Jetpack Compose اجازه تطبیق میدهد: با انیمیشن غیرفعال، durationMillis = 0 (اعمال فوری). برای View-system از ViewPropertyAnimator.withLayer() استفاده کنید و قبل از شروع انیمیشن isAnimationDisabled() را بررسی کنید.
تنظیم accessibility «حذف انیمیشن» در Android — تنها راه برای کاربر عادی برای غیرفعال کردن انیمیشن است. گزینههای توسعهدهنده فقط برای توسعهدهندگان در نظر گرفته شده و ممکن است پنهان باشند. تنظیم accessibility تضمین میشود که از طریق API سیستم به همه برنامهها منتقل شود. توسعهدهنده باید به AccessibilityManager مراجعه کند، نه به گزینههای توسعهدهنده.
تابع رسانهای CSS prefers-reduced-motion به توسعهدهندگان وب اجازه میدهد وقتی کاربر Reduce Motion را در سیستمعامل فعال کرده است، انیمیشن را غیرفعال یا جایگزین کنند. مرورگر مقدار reduce را با تنظیم سیستم فعال و no-preference را در صورت عدم تغییر تنظیم منتقل میکند. از سال ۲۰۲۰ توسط همه مرورگرهای مدرن پشتیبانی میشود: Chrome 74+، Safari 10.3+، Firefox 64+، Edge 79+.
توصیه MDN و W3C — همیشه prefers-reduced-motion: reduce را همراه با انیمیشنها تنظیم کنید. کاربری که Reduce Motion را فعال کرده نباید پالس، پارالاکس، پخش خودکار چرخفلکی و بارگذاری skeleton را ببیند. به جای انیمیشن میتوان محتوای ثابت نشان داد یا از CSS transition با حداقل مدت استفاده کرد. در زیر نمونه تطبیق کامل آورده شده است.
در prefers-reduced-motion: reduce صفحه وب باید: انیمیشنهای CSS (@keyframes) را غیرفعال کند، CSS transitions را با تغییرات فوری جایگزین کند، انیمیشنهای JavaScript (requestAnimationFrame) را متوقف کند، parallax scrolling را غیرفعال کند، چرخفلکها و اسلایدرها را متوقف کند، افکتهای skeleton را غیرفعال کند و spinner را با نشانگر ثابت جایگزین کند.
/* انیمیشنهای پایه (no-preference) */
.spinner {
width: 32px;
height: 32px;
border: 3px solid #e0e0e0;
border-top-color: #0066CC;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
.skeleton {
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e8e8e8 37%,
#f0f0f0 63%
);
background-size: 400% 100%;
animation: shimmer 1.4s ease infinite;
}
.parallax-bg {
transform: translateZ(-1px) scale(1.5);
transition: transform 0.3s ease-out;
}
/* Reduce Motion: همه چیز را غیرفعال میکنیم */
@media (prefers-reduced-motion: reduce) {
.spinner {
animation: none;
border-top-color: #0066CC;
}
.skeleton {
animation: none;
background: #f0f0f0;
}
.parallax-bg {
transform: none;
transition: none;
}
.carousel {
scroll-behavior: auto;
overflow-x: auto;
}
.fade-in {
opacity: 1;
transform: none;
}
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}در نمونه CSS از بازنشانی سراسری انیمیشن در prefers-reduced-motion: reduce استفاده شده است: همه انیمیشنها و انتقالها duration 0.01ms و iteration-count 1 میگیرند. به طور جداگانه spinner (مرز ثابت)، skeleton (پسزمینه خاکستری بدون سوسو)، پارالاکس (غیرفعال) و چرخفلک (scroll-behavior: auto به جای smooth) بازنویسی شدهاند. انتخابگر جهانی * — ایمنی برای همه عناصر.
برای JavaScript، matchMedia('(prefers-reduced-motion: reduce)').matches در دسترس است. اگر true باشد، انیمیشنها را از طریق requestAnimationFrame، setInterval یا Web Animations API اجرا نکنید. مثال: اسلایدر با reduceMotion به طور خودکار نمیچرخد، فقط با دکمهها. کتابخانههای GSAP، Framer Motion و Anime.js این بررسی را از طریق گزینههای accessibility خود پشتیبانی میکنند.
WCAG ۲.۲ (۲۰۲۳) معیار جدید ۲.۳.۳ Animation from Interactions (سطح AAA) را معرفی کرد: اگر انیمیشن از تعامل کاربر (کلیک، اسکرول، هاور) شروع میشود، باید قابل غیرفعالسازی باشد یا از ۵ ثانیه تجاوز نکند. انیمیشن غیرمرتبط با تعامل (spinner بارگذاری، progress bar) تحت این معیار قرار نمیگیرد. برای سطح AA کافی است انیمیشن تنها راه انتقال اطلاعات نباشد.
معیار ۲.۳.۳ پس از شکایات متعدد درباره بیماری حرکت ناشی از parallax scrolling و انیمیشن «کشیدن-تازهسازی» اضافه شد. W3C به همه سایتها و برنامهها توصیه میکند: عناصر را بیش از ۵ ثانیه انیمیشن ندهید، یک سوئیچ غیرفعالسازی انیمیشن ارائه دهید (از طریق پنل کنترل یا prefers-reduced-motion)، از عناصر پالسزننده و چشمکزن استفاده نکنید (خطرناک برای صرع).
برای انطباق با WCAG ۲.۲ توسعهدهنده باید: prefers-reduced-motion را بررسی کرده و با تنظیم فعال انیمیشن را غیرفعال کند، حداکثر مدت انیمیشن را ۵ ثانیه تنظیم کند (اگر انیمیشن قابل غیرفعالسازی نیست)، یک سوئیچ UI انیمیشن در تنظیمات برنامه ارائه دهد، از افکتهای پارالاکس به عنوان تنها روش ناوبری استفاده نکند و با Reduce Motion فعال در همه مرورگرها و دستگاهها تست کند.
برای تست رفتار برنامه با Reduce Motion از موارد زیر استفاده کنید: iOS Simulator (Reduce Motion را در Settings > Accessibility فعال کنید)، Android Emulator («حذف انیمیشن» را فعال کنید)، Chrome DevTools (Rendering > Emulate CSS media feature prefers-reduced-motion)، بازرس وب Safari (Reduce Motion را در macOS System Preferences > Accessibility > Display فعال کنید). بررسی کنید که محتوا بدون انیمیشن قابل دسترس و خوانا باقی میماند.
سوالات متداول
Reduce Motion — تابع accessibility سیستمعامل است که انیمیشن رابط (پارالاکس، انتقالها، بزرگنمایی آیکونها) را برای افراد مبتلا به اختلالات دهلیزی غیرفعال میکند. در Settings > Accessibility فعال میشود. سیستم از طریق UIAccessibility (iOS)، Settings.Global (Android) یا prefers-reduced-motion (CSS) به برنامهها سیگنال میدهد و توسعهدهنده میتواند انیمیشن را تطبیق دهد.
در iPhone Reduce Motion در Settings > Accessibility > Motion > Reduce Motion فعال میشود. پس از فعالسازی، پارالاکس کاغذدیوار، افکتهای iMessage، انیمیشن باز شدن برنامهها و انتقال بین صفحهها (با cross-fade جایگزین میشوند) غیرفعال میشوند. انیمیشنهای سیستمی UIKit پخش نمیشوند. تنظیم بدون راهاندازی مجدد دستگاه برای همه برنامهها اعمال میشود.
در Android انیمیشن به دو روش غیرفعال میشود: تنظیمات > دسترسپذیری > حذف انیمیشن (توصیه شده برای کاربران) یا گزینههای توسعهدهنده > مقیاس انیمیشن — خاموش کنید. روش accessibility تضمین میکند همه برنامهها سیگنال را دریافت کنند. گزینههای توسعهدهنده فقط روی انیمیشنهای سیستمی تأثیر میگذارند و ممکن است در برخی دستگاهها پنهان باشند.
تابع رسانهای CSS prefers-reduced-motion: reduce امکان غیرفعالسازی انیمیشن را در سطح استایلها فراهم میکند. توصیه میشود بازنشانی جهانی تنظیم شود: animation-duration: 0.01ms، transition-duration: 0.01ms، animation-iteration-count: 1 برای همه عناصر. به طور جداگانه کامپوننتهای خاص (spinner، skeleton، پارالاکس) را بازنویسی کنید. JavaScript از طریق matchMedia('(prefers-reduced-motion: reduce)') بررسی میشود.
WCAG ۲.۲ معیار ۲.۳.۳ (AAA) الزام میکند که انیمیشن ناشی از تعامل کاربر قابل غیرفعالسازی باشد یا از ۵ ثانیه تجاوز نکند. برای AA کافی است انیمیشن تنها راه انتقال اطلاعات نباشد. توصیه میشود همیشه prefers-reduced-motion را بررسی کنید و یک سوئیچ UI انیمیشن در تنظیمات برنامه ارائه دهید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید