Click me x5 ↓
How to use prefers-reduced-motion in SvelteKit
How to use prefers-reduced-motion in SvelteKit
I love animations, but I also don’t want to force them onto my visitors if they don’t want them. Browsers give us the prefers-reduced-motion
media query to check the user’s preferences.
CSS
For CSS animations in Svelkit, there’s no problem, you can use the media query directly.
.animation {
transition: none;
}
@media (prefers-reduced-motion: no-preference) {
.animation {
transition: transform 0.4s ease-out;
}
}
JavaScript
In JavaScript, you can check the value of the media query using window.matchMedia
. The problem is, with Sveltekit, the window
object is not accessible during server-side rendering (SSR).
You check if the window
object is avaible using the browser
variable that Sveltekit exports from $app/env
.
Here’s a function that I use for my animations
import { browser } from '$app/env';
// returns true _only_ if the user has ticked the box
const getReducedMotion = () => {
if (!browser) return;
const QUERY = '(prefers-reduced-motion: no-preference)';
const mediaQueryList = window.matchMedia(QUERY);
return !mediaQueryList.matches;
};
export default getReducedMotion;
Then, where I want to animate:
let updateRotation = () => {
const isReducedMotion = getReducedMotion();
if (isReducedMotion) return;
// TODO wrap value?
rotation = (y / innerHeight) * 360;
};