Reduce Motion — accessibility функция на операционните системи и браузърите, която изключва или намалява анимацията на интерфейса за предотвратяване на дискомфорт при потребители с вестибуларни нарушения. В iOS настройката се намира в Settings > Accessibility > Motion > Reduce Motion и изключва паралакс, анимация на преходи между екрани и ефекти на икони. В Android аналогичната опция „Премахване на анимация” се намира в Настройки > Достъпност. Според данни на W3C WCAG 2.2, прекомерната анимация може да предизвика гадене, замайване и мигрена при 15–35% от хората с вестибуларни нарушения.
Основни точки
Reduce Motion — системна настройка, която нарежда на операционната система, браузъра и приложенията да минимизират или напълно да изключат анимация, движение, мащабиране и паралакс ефекти. Функцията е предназначена за хора с вестибуларни нарушения, при които движещите се елементи на интерфейса причиняват гадене, замайване, дезориентация и мигрена.
Вестибуларната система на вътрешното ухо отговаря за чувството за равновесие и ориентация в пространството. Когато очите виждат движение на екрана, а вестибуларният апарат не усеща съответното движение на тялото, възниква сензорен конфликт. Този конфликт задейства вегетативна реакция: гадене, студена пот, замайване. Според данни на Асоциацията за вестибуларни нарушения, около 35% от хората над 40 години изпитват дискомфорт от ефектите на движение в интерфейсите.
Ключовата разлика на 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 |
|---|---|---|---|
| Паралакс на тапет | Изключва | Изключва | Н/П |
| Преходи между екрани | Заменя с fade | Изключва | CSS transitions |
| Анимация на икони | Изключва | Не влияе | CSS animations |
| Spinner на зареждане | Не влияе | Изключва | CSS animations |
| Скелетни екрани | Не влияе | Заменя с 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 с продължителност > 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: анимация на балони, конфети, лазери и фойерверки. Когато Reduce Motion е включен, iMessage ефектите се изключват автоматично. Разработчикът може да провери тази опция чрез UIAccessibility.isReduceMotionEnabled — няма отделен API за Message Effects, те са свързани с общата настройка.
В Android настройката „Премахване на анимация” се намира на две места: Настройки > Достъпност > Премахване на анимация (за accessibility настройки) и Опции за разработчици > Мащаб на анимация (за разработчици). Версията за достъпност изключва всички системни анимации, включително преходи между екрани, анимация на отваряне на приложения и ефекти на зареждане. Опциите за разработчици позволяват намаляване на мащаба до 0,5x, 0,1x или пълно изключване.
Технически Android реализира изключване на анимация чрез системни свойства: 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 — единственият начин за обикновен потребител да изключи анимация. Опциите за разработчици са предназначени само за разработчици и могат да бъдат скрити. Accessibility настройката гарантирано се предава на всички приложения чрез системния API. Разработчикът трябва да се ориентира по AccessibilityManager, а не по Опциите за разработчици.
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, не трябва да вижда пулсации, паралакс, автоматично възпроизвеждане на карусели и скелетно зареждане. Вместо анимация може да се показва статично съдържание или да се използва CSS transition с минимална продължителност. По-долу е даден пример за пълна адаптация.
При prefers-reduced-motion: reduce уеб страницата трябва да: изключи CSS анимации (@keyframes), замени CSS transitions с моментни промени, спре JavaScript анимации (requestAnimationFrame), изключи parallax scrolling, спре карусели и плъзгачи, изключи скелетни ефекти и замени 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 поддържат тази проверка чрез своите опции за достъпност.
WCAG 2.2 (2023) въведе нов критерий 2.3.3 Animation from Interactions (ниво AAA): ако анимацията се задейства от взаимодействие на потребителя (клик, превъртане, задържане), тя трябва да може да бъде изключена или да не надвишава 5 секунди. Анимацията, която не е свързана с взаимодействие (spinner на зареждане, лента за напредък), не попада под този критерий. За ниво AA е достатъчно анимацията да не е единственият начин за предаване на информация.
Критерий 2.3.3 беше добавен след множество оплаквания от прилошаване поради parallax scrolling и анимация „дръпни-обнови”. W3C препоръчва на всички сайтове и приложения: не анимирайте елементи повече от 5 секунди, предоставете превключвател за изключване на анимация (чрез контролен панел или prefers-reduced-motion), не използвайте пулсиращи и мигащи елементи (опасно за епилепсия).
За съответствие с 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 анимацията се изключва по два начина: Настройки > Достъпност > Премахване на анимация (препоръчва се за потребители) или Опции за разработчици > Мащаб на анимация — изключете. Начинът за достъпност гарантира, че всички приложения получават сигнала. Опциите за разработчици засягат само системни анимации и могат да бъдат скрити на някои устройства.
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 2.2 критерий 2.3.3 (AAA) изисква анимацията, задействана от взаимодействие на потребителя, да може да бъде изключена или да не надвишава 5 секунди. За AA е достатъчно анимацията да не е единственият начин за предаване на информация. Препоръчва се винаги да проверявате prefers-reduced-motion и да предоставяте UI превключвател за анимация в настройките на приложението.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също