Reduce Motion — una función de accesibilidad de los sistemas operativos y navegadores que desactiva o reduce la animación de la interfaz para evitar molestias en usuarios con trastornos vestibulares. En iOS, el ajuste se encuentra en Settings > Accessibility > Motion > Reduce Motion y desactiva el parallax, las animaciones de transición entre pantallas y los efectos de los iconos. En Android, la opción equivalente “Eliminar animaciones” se encuentra en Settings > Accessibility. Según W3C WCAG 2.2, la animación excesiva puede provocar náuseas, mareos y migrañas en el 15–35% de las personas con trastornos vestibulares.
Puntos clave
Reduce Motion — un ajuste del sistema que indica al sistema operativo, al navegador y a las aplicaciones que minimicen o desactiven por completo la animación, el movimiento, el escalado y los efectos de parallax. La función está pensada para personas con trastornos vestibulares, en quienes los elementos móviles de la interfaz provocan náuseas, mareos, desorientación y migrañas.
El sistema vestibular del oído interno es responsable del sentido del equilibrio y de la orientación espacial. Cuando los ojos ven movimiento en la pantalla pero el aparato vestibular no percibe el correspondiente desplazamiento del cuerpo, se produce un conflicto sensorial. Este conflicto desencadena una reacción vegetativa: náuseas, sudor frío, mareos. Según la Vestibular Disorders Association, alrededor del 35% de las personas mayores de 40 años sienten molestias por los efectos de movimiento en las interfaces.
La diferencia clave entre Reduce Motion y simplemente desactivar la animación es el nivel del sistema. Cuando está activado, el ajuste se transmite a todas las aplicaciones y sitios web a través de la API del sistema operativo o de la media feature CSS prefers-reduced-motion. El desarrollador no tiene que adivinar si el usuario quiere animación — el sistema operativo lo comunica. Esto forma parte del enfoque progressive enhancement: la animación es una mejora, no un elemento obligatorio.
Reduce Motion afecta a los efectos de parallax (desplazamiento del fondo al inclinar el dispositivo), las animaciones de transición entre pantallas (push, slide, fade), el escalado de iconos al pulsar, los efectos de mensajes (burbujas SMS), las animaciones de carga (spinner, skeleton, animación de barra de progreso), el parallax en juegos y los efectos web de parallax scrolling. Las imágenes estáticas y los vídeos no se ven afectados.
| Tipo de animación | iOS Reduce Motion | Android Remove Animation | CSS prefers-reduced-motion |
|---|---|---|---|
| Parallax del fondo | Desactiva | Desactiva | N/A |
| Transiciones entre pantallas | Sustituye por fade | Desactiva | CSS transitions |
| Animación de iconos | Desactiva | Sin efecto | CSS animations |
| Spinner de carga | Sin efecto | Desactiva | CSS animations |
| Pantallas skeleton | Sin efecto | Sustituye por estático | CSS animations |
La audiencia principal de Reduce Motion son las personas con trastornos vestibulares (enfermedad de Ménière, laberintitis, VPPB), migraña (especialmente con aura), cinetosis (mareo por movimiento en el transporte) y algunas formas de epilepsia. La función también es útil para los usuarios mayores — los cambios relacionados con la edad en el aparato vestibular aumentan la sensibilidad al movimiento — y para los usuarios con TDAH, ya que los elementos en movimiento distraen de la lectura.
En iOS, Reduce Motion se encuentra en Settings > Accessibility > Motion e incluye tres opciones: Reduce Motion (el interruptor principal), Auto-Play Message Effects (reproducción automática de efectos de iMessage) y Auto-Play Video Previews (reproducción automática de vídeos en el App Store). Reduce Motion es el más potente: desactiva el parallax del fondo, la animación de apertura de aplicaciones (zoom), las transiciones entre pantallas (push se sustituye por cross-fade) y los efectos de iconos en la pantalla de inicio.
Técnicamente, iOS implementa Reduce Motion a nivel de UIKit mediante UIView animations y UIViewControllerAnimatedTransitioning. Con el ajuste activado, UIView.animate con una duración > 0 se reduce a 0,01 segundos, y UIViewController.transitionDuration devuelve 0. Para el parallax, iOS desactiva UIInterpolatingMotionEffect en UIWindow. El desarrollador puede comprobar el estado mediante UIAccessibility.isReduceMotionEnabled.
Un desarrollador puede adaptar la animación en iOS a Reduce Motion: sustituir transiciones complejas por efectos fade, desactivar el parallax en componentes de UI personalizados y acortar las duraciones de las animaciones. SwiftUI proporciona un modificador especial .animation(nil) cuando reduceMotion está activo.
import UIKit
class MotionManager {
// Comprobar el estado de Reduce Motion
static var isReduceMotionEnabled: Bool {
return UIAccessibility.isReduceMotionEnabled
}
// Animación segura que respeta 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 — modificador para 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 }
}
}
// Suscripción al cambio de Reduce Motion
NotificationCenter.default.addObserver(
self,
selector: #selector(motionStatusChanged),
name: UIAccessibility.reduceMotionStatusDidChangeNotification,
object: nil
)La clase MotionManager comprueba isReduceMotionEnabled y adapta la duración de la animación: cuando Reduce Motion está activo, la duración se reduce a 0,01 segundos (prácticamente instantánea). El modificador .animation(nil) de SwiftUI desactiva por completo la animación cuando reduceMotion == true. La suscripción a reduceMotionStatusDidChangeNotification permite cambiar dinámicamente la animación sin reiniciar la aplicación.
Una opción separada de iOS — Auto-Play Message Effects — controla la reproducción de efectos en iMessage: animación de globos, confeti, láseres y fuegos artificiales. Cuando Reduce Motion está activado, los efectos de iMessage se desactivan automáticamente. Un desarrollador puede comprobar esta opción mediante UIAccessibility.isReduceMotionEnabled — no existe una API separada para Message Effects; están vinculados al ajuste general.
En Android, el ajuste “Eliminar animaciones” se encuentra en dos lugares: Settings > Accessibility > Eliminar animaciones (para los ajustes de accesibilidad) y Opciones de desarrollador > Escala de animación (para desarrolladores). La versión de accesibilidad desactiva todas las animaciones del sistema, incluidas las transiciones entre pantallas, la animación de apertura de aplicaciones y los efectos de carga. Las Developer Options permiten reducir la escala a 0,5x, 0,1x o desactivarla por completo.
Técnicamente, Android implementa la desactivación de animaciones mediante propiedades del sistema: window_animation_scale, transition_animation_scale y animator_duration_scale. Con el ajuste de accesibilidad, las tres se establecen en 0. El Launcher del sistema y las aplicaciones del sistema comprueban estos valores. Para las aplicaciones de terceros, Android recomienda usar Jetpack Compose y el sistema View, que leen automáticamente el ajuste del sistema a través de AnimationScaleObserver.
Un desarrollador puede comprobar el estado de la animación en Android mediante Settings.Global y adaptar la UI. Jetpack Compose ofrece AnimationScaleObserver para el ajuste automático. El valor clave es animator_duration_scale: si es 0, la animación está completamente desactivada.
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 {
// Comprobar si la animación está desactivada
fun isAnimationDisabled(context: Context): Boolean {
return try {
Settings.Global.getFloat(
context.contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE
) == 0f
} catch (e: Settings.SettingNotFoundException) {
false
}
}
// Observar los cambios de animación (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 — animación que respeta los ajustes
@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 con animación
}
La clase AndroidMotionHelper comprueba ANIMATOR_DURATION_SCALE mediante Settings.Global, proporciona un ContentObserver para rastrear los cambios y permite que las animaciones de Jetpack Compose se adapten: cuando la animación está desactivada, durationMillis = 0 (aplicación instantánea). Para el sistema View, use ViewPropertyAnimator.withLayer() y compruebe isAnimationDisabled() antes de iniciar una animación.
El ajuste de accesibilidad “Eliminar animaciones” en Android es la única forma de que un usuario normal desactive la animación. Las Developer Options están pensadas solo para desarrolladores y pueden estar ocultas. El ajuste de accesibilidad se transmite garantizadamente a todas las aplicaciones a través de la API del sistema. El desarrollador debe apoyarse en AccessibilityManager y no en las Developer Options.
La media feature CSS prefers-reduced-motion permite a los desarrolladores web desactivar o sustituir la animación cuando el usuario ha activado Reduce Motion en el sistema operativo. El navegador informa del valor reduce cuando el ajuste del sistema está activo y no-preference cuando no está modificado. Es compatible con todos los navegadores modernos desde 2020: Chrome 74+, Safari 10.3+, Firefox 64+, Edge 79+.
La recomendación de MDN y W3C es especificar siempre prefers-reduced-motion: reduce junto con las animaciones. Un usuario que haya activado Reduce Motion no debería ver pulsaciones, parallax, carruseles de reproducción automática ni carga skeleton. En lugar de la animación, se puede mostrar contenido estático o usar una transición CSS con duración mínima. A continuación se muestra un ejemplo de adaptación completa.
Con prefers-reduced-motion: reduce, una página web debe: desactivar las animaciones CSS (@keyframes), sustituir las transiciones CSS por cambios instantáneos, detener las animaciones de JavaScript (requestAnimationFrame), desactivar el parallax scrolling, detener los carruseles y deslizadores, desactivar los efectos skeleton y sustituir el spinner por un indicador estático.
/* Animaciones básicas (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: desactivamos todo */
@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; }
}En el ejemplo de CSS se usa un reinicio global de la animación para prefers-reduced-motion: reduce: todas las animaciones y transiciones reciben una duración de 0,01ms e iteration-count 1. Por separado se redefinen el spinner (borde estático), el skeleton (fondo gris sin parpadeo), el parallax (desactivado) y el carrusel (scroll-behavior: auto en lugar de smooth). El selector universal * es una red de seguridad para todos los elementos.
Para JavaScript está disponible matchMedia('(prefers-reduced-motion: reduce)').matches. Si es true — no ejecute animaciones mediante requestAnimationFrame, setInterval o la Web Animations API. Ejemplo: un deslizador con reduceMotion no rota automáticamente, solo con los botones. Librerías como GSAP, Framer Motion y Anime.js admiten esta comprobación a través de sus opciones de accesibilidad.
WCAG 2.2 (2023) introdujo un nuevo criterio 2.3.3 Animation from Interactions (nivel AAA): si la animación se activa por la interacción del usuario (clic, desplazamiento, hover), debe poder desactivarse o no superar los 5 segundos. La animación no relacionada con la interacción (spinner de carga, barra de progreso) no entra en este criterio. Para el nivel AA basta con que la animación no sea la única forma de transmitir información.
El criterio 2.3.3 se añadió tras numerosas quejas por motion sickness provocado por el parallax scrolling y la animación “pull-to-refresh”. W3C recomienda a todos los sitios y aplicaciones: no animar elementos durante más de 5 segundos, ofrecer un interruptor para desactivar la animación (mediante un panel de control o prefers-reduced-motion), y no usar elementos pulsantes y parpadeantes (peligroso para la epilepsia).
Para cumplir WCAG 2.2, un desarrollador debe: comprobar prefers-reduced-motion y desactivar la animación cuando el ajuste esté activo, fijar una duración máxima de animación de 5 segundos (si la animación no puede desactivarse), ofrecer un interruptor de animación en la UI de los ajustes de la aplicación, no usar efectos de parallax como única forma de navegación y probar con Reduce Motion activado en todos los navegadores y dispositivos.
Para probar el comportamiento de la aplicación con Reduce Motion, use: iOS Simulator (activar Reduce Motion en Settings > Accessibility), Android Emulator (activar “Eliminar animaciones”), Chrome DevTools (Rendering > Emulate CSS media feature prefers-reduced-motion) y el inspector web de Safari (activar Reduce Motion en macOS System Preferences > Accessibility > Display). Compruebe que el contenido sigue siendo accesible y legible sin animación.
Preguntas frecuentes
Reduce Motion — una función de accesibilidad del sistema operativo que desactiva la animación de la interfaz (parallax, transiciones, escalado de iconos) para personas con trastornos vestibulares. Se activa en Settings > Accessibility. El sistema transmite la señal a las aplicaciones mediante UIAccessibility (iOS), Settings.Global (Android) o prefers-reduced-motion (CSS), y el desarrollador puede adaptar la animación.
En un iPhone, Reduce Motion se activa en Settings > Accessibility > Motion > Reduce Motion. Una vez activado, se desactivan el parallax del fondo, los efectos de iMessage, la animación de apertura de aplicaciones y las transiciones entre pantallas (sustituidas por cross-fade). Las animaciones del sistema UIKit no se reproducen. El ajuste se aplica a todas las aplicaciones sin reiniciar el dispositivo.
En Android, la animación se desactiva de dos formas: Settings > Accessibility > Eliminar animaciones (recomendado para usuarios) u Opciones de desarrollador > Escala de animación — desactivarla. El método de accesibilidad garantiza que todas las aplicaciones reciban la señal. Las Developer Options solo afectan a las animaciones del sistema y pueden estar ocultas en algunos dispositivos.
La media feature CSS prefers-reduced-motion: reduce permite desactivar la animación a nivel de estilos. Se recomienda establecer un reinicio universal: animation-duration: 0,01ms, transition-duration: 0,01ms, animation-iteration-count: 1 para todos los elementos. Redefina por separado los componentes específicos (spinner, skeleton, parallax). JavaScript se comprueba mediante matchMedia('(prefers-reduced-motion: reduce)').
WCAG 2.2 el criterio 2.3.3 (AAA) exige que la animación activada por la interacción del usuario sea desactivable o no supere los 5 segundos. Para AA basta con que la animación no sea la única forma de transmitir información. Se recomienda comprobar siempre prefers-reduced-motion y ofrecer un interruptor de animación en la UI de los ajustes de la aplicación.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también