Reduce Motion — accessibility-функція операційних систем і браузерів, яка вимикає або скорочує анімацію інтерфейсу для запобігання дискомфорту в користувачів із вестибулярними порушеннями. В iOS налаштування знаходиться в Settings > Accessibility > Motion > Reduce Motion і вимикає паралакс, анімацію переходів між екранами та ефекти іконок. В Android аналогічний параметр «Видалити анімацію» розташований у Налаштуваннях > Спеціальні можливості. За даними W3C WCAG 2.2, надмірна анімація може викликати нудоту, запаморочення та мігрень у 15–35% людей із vestibular disorders.
Головне
Reduce Motion — системне налаштування, що зобов'язує операційну систему, браузер і застосунки мінімізувати або повністю вимкнути анімацію, переміщення, масштабування та паралакс-ефекти. Функція призначена для людей із вестибулярними розладами (vestibular disorders), у яких рухомі елементи інтерфейсу викликають нудоту, запаморочення, дезорієнтацію та мігрень.
Вестибулярна система внутрішнього вуха відповідає за відчуття рівноваги та орієнтації в просторі. Коли очі бачать рух на екрані, а вестибулярний апарат не відчуває відповідного переміщення тіла, виникає сенсорний конфлікт. Цей конфлікт запускає вегетативну реакцію: нудоту, холодний піт, запаморочення. За даними Vestibular Disorders Association, близько 35% людей старших за 40 років відчувають дискомфорт від motion-ефектів в інтерфейсах.
Ключова відмінність Reduce Motion від простого вимкнення анімації — системний рівень. Увімкнене налаштування передається всім застосункам і веб-сайтам через API ОС або CSS-медіа-функцію prefers-reduced-motion. Розробнику не потрібно вгадувати, чи хоче користувач анімацію — ОС повідомляє про це. Це частина підходу 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 |
|---|---|---|---|
| Паралакс шпалер | Вимикає | Вимикає | N/A |
| Переходи між екранами | Замінює на fade | Вимикає | CSS transitions |
| Анімація іконок | Вимикає | Не впливає | CSS animations |
| Spinner завантаження | Не впливає | Вимикає | CSS animations |
| Skeleton screens | Не впливає | Замінює на static | CSS animations |
Основна аудиторія Reduce Motion — люди з vestibular disorders (хвороба Меньєра, лабіринтит, BPPV), мігренню (особливо з аурою), kinetosis (закачування в транспорті) та деякими формами epilepsy. Функція також корисна для літніх користувачів — вікові зміни вестибулярного апарату підвищують чутливість до motion — і для користувачів із СДУГ — рухомі елементи відволікають від читання.
В 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 тривалістю > 0 скорочується до 0.01 сек, а UIViewController.transitionDuration повертає 0. Для паралаксу iOS вимикає UIInterpolatingMotionEffect на UIWindow. Розробник може перевірити стан через UIAccessibility.isReduceMotionEnabled.
Розробник може адаптувати анімацію в iOS під Reduce Motion: замінити складні переходи на fade-ефекти, вимкнути паралакс у кастомних UI-компонентах і скоротити тривалість анімацій. SwiftUI надає спеціальний модифікатор .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 — модифікатор для 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 тривалість скорочується до 0.01 сек (фактично миттєво). Модифікатор SwiftUI .animation(nil) повністю вимикає анімацію, коли reduceMotion == true. Підписка на reduceMotionStatusDidChangeNotification дозволяє динамічно перемикати анімацію без перезавантаження застосунку.
Окрема опція iOS — Auto-Play Message Effects — керує відтворенням ефектів в iMessage: balloon-анімацією, конфеті, лазерами та феєрверками. За увімкненого Reduce Motion ефекти iMessage автоматично вимикаються. Розробник може перевірити цю опцію через UIAccessibility.isReduceMotionEnabled — окремого API для Message Effects немає, вони прив'язані до загального налаштування.
В Android налаштування «Видалити анімацію» (Remove animations) знаходиться у двох місцях: Налаштування > Спеціальні можливості > Видалити анімацію (для accessibility-налаштувань) і Параметри розробника > Масштаб анімації (для розробників). Accessibility-версія вимикає всі системні анімації, зокрема переходи між екранами, анімацію відкриття застосунків та ефекти завантаження. Developer Options дозволяють зменшити масштаб до 0.5x, 0.1x або вимкнути повністю.
Технічно Android реалізує вимкнення анімації через системні properties: window_animation_scale, transition_animation_scale і animator_duration_scale. За accessibility-налаштування всі три отримують значення 0. Системний Launcher і системні застосунки перевіряють ці значення. Для сторонніх застосунків Android рекомендує використовувати Jetpack Compose та View system, які автоматично зчитують системне налаштування через AnimationScaleObserver.
Розробник може перевірити стан анімації в Android через Settings.Global і адаптувати UI. Jetpack Compose надає AnimationScaleObserver для автоматичного підлаштування. Ключове значення — animator_duration_scale: якщо 0, анімація вимкнена повністю.
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-системи використовуйте ViewPropertyAnimator.withLayer() і перевірку isAnimationDisabled() перед запуском анімації.
Accessibility-налаштування «Видалити анімацію» в Android — єдиний спосіб для звичайного користувача вимкнути анімацію. Developer Options (параметри розробника) призначені тільки для розробників і можуть бути приховані. Accessibility-налаштування гарантовано передається всім застосункам через системний API. Розробнику слід орієнтуватися саме на AccessibilityManager, а не на Developer Options.
CSS-медіа-функція prefers-reduced-motion дозволяє веб-розробникам вимикати або замінювати анімацію, коли користувач увімкнув Reduce Motion в операційній системі. Браузер передає значення reduce за активної системної настройки, no-preference — якщо настройку не змінено. Підтримується всіма сучасними браузерами з 2020 року: 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 (сірий фон без мерехтіння), parallax (вимкнено) і carousel (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 2.2 (2023) ввів новий критерій 2.3.3 Animation from Interactions (рівень AAA): якщо анімація запускається від взаємодії користувача (клік, скролл, наведення), вона повинна бути вимкненою або не перевищувати 5 секунд. Анімація, не пов'язана зі взаємодією (завантажувальний спіннер, progress bar), під цей критерій не потрапляє. Для рівня AA достатньо, щоб анімація не була єдиним способом передачі інформації.
Критерій 2.3.3 був доданий після численних скарг на motion sickness від паралакс-скролінгу та анімації «потягнути-оновити» (pull-to-refresh). W3C рекомендує всім сайтам і застосункам: не анімувати елементи понад 5 секунд, надавати перемикач вимкнення анімації (через control panel або prefers-reduced-motion), не використовувати пульсуючі та спалахуючі елементи (небезпечно для epilepsy).
Для відповідності WCAG 2.2 розробнику потрібно: перевірити prefers-reduced-motion і вимкнути анімацію за активної настройки, встановити максимальну тривалість анімації 5 секунд (якщо анімацію не можна вимкнути), надати 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-спосіб гарантує, що всі застосунки отримають сигнал. Developer Options впливають лише на системні анімації та можуть бути приховані на деяких пристроях.
CSS-медіа-функція prefers-reduced-motion: reduce дозволяє вимкнути анімацію на рівні стилів. Рекомендується задати універсальний скид: animation-duration: 0.01ms, transition-duration: 0.01ms, animation-iteration-count: 1 для всіх елементів. Окремо перевизначити конкретні компоненти (spinner, skeleton, parallax). JavaScript перевіряється через matchMedia('(prefers-reduced-motion: reduce)').
WCAG 2.2 критерій 2.3.3 (AAA) вимагає, щоб анімація від взаємодії користувача була вимкненою або не перевищувала 5 секунд. Для AA достатньо, щоб анімація не була єдиним способом передачі інформації. Рекомендується завжди перевіряти prefers-reduced-motion і надавати UI-перемикач анімації в налаштуваннях застосунку.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також