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 |
| 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 са трајањем > 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 подешавања) и Опције за програмере > Размера анимације (за програмере). 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 не би требало да види пулсације, паралакс, аутоматску репродукцију карусела и 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 2.2 (2023) је увео нови критеријум 2.3.3 Animation from Interactions (ниво AAA): ако се анимација покреће од интеракције корисника (клик, скроловање, прелазак мишем), мора бити искључива или не трајати дуже од 5 секунди. Анимација која није повезана са интеракцијом (spinner учитавања, progress bar) не потпада под овај критеријум. За ниво 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-у анимација се искључује на два начина: Подешавања > Приступачност > Уклони анимацију (препоручује се за кориснике) или Опције за програмере > Размера анимације — искључите. 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 2.2 критеријум 2.3.3 (AAA) захтева да анимација покренута интеракцијом корисника буде искључива или не траје дуже од 5 секунди. За AA довољно је да анимација није једини начин преношења информација. Препоручује се увек проверавати prefers-reduced-motion и обезбедити UI прекидач анимације у подешавањима апликације.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође