Reduce Motion — funkce accessibility operačních systémů a prohlížečů, která vypíná nebo omezuje animaci rozhraní, aby se předešlo nepohodlí u uživatelů s vestibulárními poruchami. V iOS se nastavení nachází v Settings > Accessibility > Motion > Reduce Motion a vypíná paralaxu, animaci přechodů mezi obrazovkami a efekty ikon. V Androidu se analogická možnost „Odstranit animaci” nachází v Nastavení > Přístupnost. Podle údajů W3C WCAG 2.2 může nadměrná animace způsobit nevolnost, závratě a migrénu u 15–35 % lidí s vestibulárními poruchami.
Hlavní body
Reduce Motion — systémové nastavení, které nařizuje operačnímu systému, prohlížeči a aplikacím minimalizovat nebo úplně vypnout animaci, pohyb, škálování a efekty paralaxy. Funkce je určena pro lidi s vestibulárními poruchami, u nichž pohyblivé prvky rozhraní způsobují nevolnost, závratě, dezorientaci a migrénu.
Vestibulární systém vnitřního ucha je zodpovědný za pocit rovnováhy a orientaci v prostoru. Když oči vidí pohyb na obrazovce, ale vestibulární aparát necítí odpovídající pohyb těla, vzniká smyslový konflikt. Tento konflikt spouští vegetativní reakci: nevolnost, studený pot, závratě. Podle údajů Asociace pro vestibulární poruchy pociťuje nepohodlí z pohybových efektů v rozhraních přibližně 35 % lidí starších 40 let.
Klíčový rozdíl Reduce Motion oproti prostému vypnutí animace — systémová úroveň. Zapnuté nastavení se předává všem aplikacím a webovým stránkám přes API operačního systému nebo CSS mediální funkci prefers-reduced-motion. Vývojář nemusí hádat, zda uživatel chce animaci — systém to oznamuje. To je součástí přístupu progressive enhancement: animace je vylepšení, nikoli povinný prvek.
Reduce Motion ovlivňuje efekty paralaxy (posun pozadí při naklonění zařízení), animaci přechodů mezi obrazovkami (push, slide, fade), škálování ikon při stisknutí, efekty zpráv (bubliny SMS), animaci načítání (spinner, skeleton, progress bar animation), paralaxu ve hrách a webové efekty parallax scrolling. Statické obrázky a videa nejsou ovlivněny.
| Typ animace | iOS Reduce Motion | Android Remove Animation | CSS prefers-reduced-motion |
|---|---|---|---|
| Paralaxa tapety | Vypíná | Vypíná | N/A |
| Přechody mezi obrazovkami | Nahrazuje fade | Vypíná | CSS transitions |
| Animace ikon | Vypíná | Neovlivňuje | CSS animations |
| Spinner načítání | Neovlivňuje | Vypíná | CSS animations |
| Obrazovky skeleton | Neovlivňuje | Nahrazuje static | CSS animations |
Hlavní cílová skupina Reduce Motion — lidé s vestibulárními poruchami (Meniérova choroba, labyrinthitida, BPPV), migrénou (zejména s aurou), kinetózou (nevolnost v dopravě) a některými formami epilepsie. Funkce je také užitečná pro starší uživatele — věkové změny vestibulárního aparátu zvyšují citlivost na pohyb, a pro uživatele s ADHD — pohyblivé prvky odvádějí pozornost od čtení.
V iOS se Reduce Motion nachází v Settings > Accessibility > Motion a zahrnuje tři možnosti: Reduce Motion (hlavní přepínač), Auto-Play Message Effects (automatické přehrávání efektů iMessage) a Auto-Play Video Previews (automatické přehrávání videí v App Store). Reduce Motion je nejvýkonnější: vypíná paralaxu tapety, animaci otevírání aplikací (zoom), přechody mezi obrazovkami (push je nahrazen cross-fade) a efekty ikon na domovské obrazovce.
Technicky iOS implementuje Reduce Motion na úrovni UIKit prostřednictvím UIView animations a UIViewControllerAnimatedTransitioning. Při zapnutém nastavení se UIView.animate s dobou trvání > 0 zkrátí na 0,01 s a UIViewController.transitionDuration vrací 0. Pro paralaxu iOS vypíná UIInterpolatingMotionEffect na UIWindow. Vývojář může zkontrolovat stav pomocí UIAccessibility.isReduceMotionEnabled.
Vývojář může přizpůsobit animaci v iOS pro Reduce Motion: nahradit složité přechody fade efekty, vypnout paralaxu ve vlastních UI komponentách a zkrátit dobu trvání animací. SwiftUI poskytuje speciální modifikátor .animation(nil), když je reduceMotion aktivní.
import UIKit
class MotionManager {
// Kontrola stavu Reduce Motion
static var isReduceMotionEnabled: Bool {
return UIAccessibility.isReduceMotionEnabled
}
// Bezpečná animace s ohledem na 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 — modifikátor pro 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 }
}
}
// Předplatné změny Reduce Motion
NotificationCenter.default.addObserver(
self,
selector: #selector(motionStatusChanged),
name: UIAccessibility.reduceMotionStatusDidChangeNotification,
object: nil
)Třída MotionManager kontroluje isReduceMotionEnabled a přizpůsobuje dobu trvání animace: při aktivním Reduce Motion se doba zkrátí na 0,01 s (prakticky okamžitě). Modifikátor SwiftUI .animation(nil) zcela vypíná animaci, když reduceMotion == true. Předplatné reduceMotionStatusDidChangeNotification umožňuje dynamicky přepínat animaci bez opětovného načítání aplikace.
Samostatná možnost iOS — Auto-Play Message Effects — řídí přehrávání efektů v iMessage: animaci balónků, konfety, lasery a ohňostroje. Při zapnutém Reduce Motion jsou efekty iMessage automaticky vypnuty. Vývojář může tuto možnost zkontrolovat pomocí UIAccessibility.isReduceMotionEnabled — pro Message Effects neexistuje samostatné API, jsou vázány na obecné nastavení.
V Androidu se nastavení „Odstranit animaci” nachází na dvou místech: Nastavení > Přístupnost > Odstranit animaci (pro nastavení přístupnosti) a Možnosti pro vývojáře > Měřítko animace (pro vývojáře). Verze pro přístupnost vypíná všechny systémové animace, včetně přechodů mezi obrazovkami, animace otevírání aplikací a efektů načítání. Možnosti pro vývojáře umožňují snížit měřítko na 0,5x, 0,1x nebo úplně vypnout.
Technicky Android implementuje vypínání animace prostřednictvím systémových vlastností: window_animation_scale, transition_animation_scale a animator_duration_scale. Při nastavení přístupnosti všechny tři získají hodnotu 0. Systémový spouštěč a systémové aplikace tyto hodnoty kontrolují. Pro aplikace třetích stran Android doporučuje používat Jetpack Compose a View system, které automaticky čtou systémové nastavení prostřednictvím AnimationScaleObserver.
Vývojář může zkontrolovat stav animace v Androidu pomocí Settings.Global a přizpůsobit UI. Jetpack Compose poskytuje AnimationScaleObserver pro automatické přizpůsobení. Klíčová hodnota — animator_duration_scale: pokud je 0, animace je zcela vypnuta.
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 {
// Kontrola vypnutí animace
fun isAnimationDisabled(context: Context): Boolean {
return try {
Settings.Global.getFloat(
context.contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE
) == 0f
} catch (e: Settings.SettingNotFoundException) {
false
}
}
// Sledování změny animace (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 — animace s ohledem na nastavení
@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 s animací
}
Třída AndroidMotionHelper kontroluje ANIMATOR_DURATION_SCALE prostřednictvím Settings.Global, poskytuje ContentObserver pro sledování změn a umožňuje animacím Jetpack Compose se přizpůsobit: při vypnuté animaci je durationMillis = 0 (okamžité použití). Pro View systém použijte ViewPropertyAnimator.withLayer() a před spuštěním animace zkontrolujte isAnimationDisabled().
Nastavení přístupnosti „Odstranit animaci” v Androidu — jediný způsob pro běžného uživatele, jak vypnout animaci. Možnosti pro vývojáře jsou určeny pouze pro vývojáře a mohou být skryty. Nastavení přístupnosti je zaručeně předáno všem aplikacím prostřednictvím systémového API. Vývojář by se měl řídit podle AccessibilityManager, nikoli podle Možností pro vývojáře.
Mediální funkce CSS prefers-reduced-motion umožňuje vývojářům webu vypnout nebo nahradit animaci, když uživatel zapnul Reduce Motion v operačním systému. Prohlížeč předává hodnotu reduce při aktivním systémovém nastavení, no-preference — pokud nastavení nebylo změněno. Podporována všemi moderními prohlížeči od roku 2020: Chrome 74+, Safari 10.3+, Firefox 64+, Edge 79+.
Doporučení MDN a W3C — vždy nastavte prefers-reduced-motion: reduce spolu s animacemi. Uživatel, který zapnul Reduce Motion, by neměl vidět pulsaci, paralaxu, automatické přehrávání karuselů a skeleton načítání. Místo animace lze zobrazit statický obsah nebo použít CSS transition s minimální dobou trvání. Níže je uveden příklad úplné adaptace.
Při prefers-reduced-motion: reduce by webová stránka měla: vypnout CSS animace (@keyframes), nahradit CSS transitions okamžitými změnami, zastavit JavaScript animace (requestAnimationFrame), vypnout parallax scrolling, zastavit karusely a posuvníky, vypnout skeleton efekty a nahradit spinner statickým indikátorem.
/* Základní animace (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: vše vypínáme */
@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; }
}V příkladu CSS je použito globální resetování animace při prefers-reduced-motion: reduce: všechny animace a přechody získají duration 0.01ms a iteration-count 1. Samostatně jsou přepsány spinner (statický okraj), skeleton (šedé pozadí bez blikání), paralaxa (vypnuta) a karusel (scroll-behavior: auto místo smooth). Univerzální selektor * — ochrana pro všechny prvky.
Pro JavaScript je k dispozici matchMedia('(prefers-reduced-motion: reduce)').matches. Pokud je true — nespouštějte animace prostřednictvím requestAnimationFrame, setInterval nebo Web Animations API. Příklad: posuvník s reduceMotion se neotáčí automaticky, pouze pomocí tlačítek. Knihovny GSAP, Framer Motion a Anime.js podporují tuto kontrolu prostřednictvím svých možností přístupnosti.
WCAG 2.2 (2023) zavedl nové kritérium 2.3.3 Animation from Interactions (úroveň AAA): pokud je animace spuštěna interakcí uživatele (kliknutí, rolování, najetí), musí být vypnutelná nebo nesmí přesáhnout 5 sekund. Animace nesouvisející s interakcí (spinner načítání, progress bar) pod toto kritérium nespadá. Pro úroveň AA stačí, aby animace nebyla jediným způsobem předávání informací.
Kritérium 2.3.3 bylo přidáno po četných stížnostech na kinetózu z parallax scrollingu a animace „zatáhni-obnov”. W3C doporučuje všem webům a aplikacím: neanimujte prvky déle než 5 sekund, poskytněte přepínač vypnutí animace (prostřednictvím ovládacího panelu nebo prefers-reduced-motion), nepoužívejte pulzující a blikající prvky (nebezpečné pro epilepsii).
Pro soulad s WCAG 2.2 by vývojář měl: zkontrolovat prefers-reduced-motion a vypnout animaci při aktivním nastavení, nastavit maximální dobu trvání animace na 5 sekund (pokud animaci nelze vypnout), poskytnout přepínač UI animace v nastavení aplikace, nepoužívat efekty paralaxy jako jediný způsob navigace a testovat se zapnutým Reduce Motion ve všech prohlížečích a na všech zařízeních.
Pro testování chování aplikace s Reduce Motion použijte: iOS Simulator (zapněte Reduce Motion v Settings > Accessibility), Android Emulator (zapněte „Odstranit animaci”), Chrome DevTools (Rendering > Emulate CSS media feature prefers-reduced-motion), webový inspektor Safari (zapněte Reduce Motion v macOS System Preferences > Accessibility > Display). Zkontrolujte, že obsah zůstává přístupný a čitelný bez animace.
Často kladené otázky
Reduce Motion — funkce accessibility operačního systému, která vypíná animaci rozhraní (paralaxu, přechody, škálování ikon) pro lidi s vestibulárními poruchami. Zapíná se v Settings > Accessibility. Systém předává signál aplikacím prostřednictvím UIAccessibility (iOS), Settings.Global (Android) nebo prefers-reduced-motion (CSS) a vývojář může animaci přizpůsobit.
Na iPhonu se Reduce Motion zapíná v Settings > Accessibility > Motion > Reduce Motion. Po zapnutí se vypínají: paralaxa tapety, efekty iMessage, animace otevírání aplikací a přechody mezi obrazovkami (nahrazeny cross-fade). Systémové animace UIKit se nepřehrávají. Nastavení se aplikuje na všechny aplikace bez restartu zařízení.
V Androidu se animace vypíná dvěma způsoby: Nastavení > Přístupnost > Odstranit animaci (doporučeno pro uživatele) nebo Možnosti pro vývojáře > Měřítko animace — vypnout. Způsob přístupnosti zaručuje, že všechny aplikace obdrží signál. Možnosti pro vývojáře ovlivňují pouze systémové animace a mohou být na některých zařízeních skryty.
Mediální funkce CSS prefers-reduced-motion: reduce umožňuje vypnout animaci na úrovni stylů. Doporučuje se nastavit univerzální reset: animation-duration: 0.01ms, transition-duration: 0.01ms, animation-iteration-count: 1 pro všechny prvky. Samostatně přepsat konkrétní komponenty (spinner, skeleton, paralaxu). JavaScript se kontroluje pomocí matchMedia('(prefers-reduced-motion: reduce)').
WCAG 2.2 kritérium 2.3.3 (AAA) vyžaduje, aby animace spuštěná interakcí uživatele byla vypnutelná nebo nepřesáhla 5 sekund. Pro AA stačí, aby animace nebyla jediným způsobem předávání informací. Doporučuje se vždy kontrolovat prefers-reduced-motion a poskytnout přepínač UI animace v nastavení aplikace.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také