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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также