BlogAccessibility
Reduced motion in Webflow, without the blank pause
Most reduced-motion snippets cut the duration and forget the delay, which turns every staggered entrance into an empty pause.
Break it yourself
A live demo. It measures its own result in your browser.
To respect reduced motion in Webflow, set the reduced-motion option on each interaction and add a CSS rule that zeroes animation and transition delays as well as their durations. Most snippets only shorten the duration, so a staggered entrance still waits out its delay on a blank page and then appears all at once.
The short answer
A visitor who turns on “Reduce motion” in their operating system is asking for less movement, not for a slower page. Three things decide whether your Webflow site gives them that:
- Your custom CSS rule for
prefers-reduced-motionmust cancel delays, not only durations. Otherwise content waits on a blank page. - Anything that loops forever needs
animation: none, scoped to a class you put on looping elements. Shortening a loop only makes it spin faster. - Motion written as inline styles by a script or an interaction is out of reach of any stylesheet. Check the preference in JavaScript too.
We learned all three on our own site, which is why the rest of this note is about the traps rather than the theory.
What the usual snippet does
Many Webflow sites carry a reduced-motion snippet in Site settings, Custom code, inside the head tag. A common version looks like this:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}The idea is sound. Setting the duration to almost nothing, rather than removing the animation, means every animation still runs and still fires its end events, so scripts that wait for an animation to finish keep working. The element simply arrives at its end state at once.
The problem is what the rule leaves out. It says nothing about animation-delay or transition-delay, and it says nothing about how many times an animation repeats.
The delay nobody shortened
Staggered entrances are built with delays: the first card fades in at 0s, the second at 0.1s, the third at 0.2s. The animation usually starts from opacity: 0, and it carries a fill mode of both (or backwards) so the element does not flash visible before its turn.
That fill mode is the trap. By the CSS spec, an animation with a backwards fill applies its first keyframe during the delay. The snippet shrinks the animation itself to 0.01ms, but the delay is untouched, so each element sits in its hidden first frame for the full delay and then snaps to visible. With reduced motion on, a graceful stagger turns into a blank pause followed by everything popping in at once. That is arguably worse than the motion the visitor asked to avoid.
On our own site, with reduced motion turned on, four of the six entrance blocks on the home page stayed invisible until 0.4s, and on the work page all four did. With the setting off, the same pages looked fine, which is exactly why this kind of bug survives.
The fix is two lines in the same rule:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-delay: 0s !important;
transition-duration: 0.01ms !important;
transition-delay: 0s !important;
scroll-behavior: auto !important;
}
}With the delays at zero, every element lands in its final state on the first frame, which is what the visitor asked for.
Loops that never stop
The same rule only shortens. A marquee, a floating badge or a spinning icon set to animation-iteration-count: infinite keeps running after the rule applies, now at 0.01ms per cycle. Depending on the keyframes, that reads as a flicker or a jitter, which is more motion, not less.
Loops need to be switched off, not sped up. Put one class on everything that loops and stop those elements completely:
@media (prefers-reduced-motion: reduce) {
.anim-loop {
animation: none !important;
}
}Scope it to that class, never to a broad selector. An earlier version of our rule targeted svg, and it killed an SVG animation across the whole document. Our loops are now gated by one class, and nothing else is caught by accident.
WCAG 2.2.2 Pause, Stop, Hide (level A) applies to anything that moves on its own for more than five seconds, such as a logo marquee, whatever the visitor’s settings are. Honouring prefers-reduced-motion does not replace a pause control for that kind of content.
Motion the stylesheet cannot reach
A CSS rule changes CSS animations and transitions. It does not touch a transform that a script writes straight onto an element as an inline style, which is how many scroll effects, parallax scripts and cursor followers work. An inline style beats the class rule, so the element keeps moving. We wrote about the same mechanism from the layout side in why your Webflow mobile styles refuse to apply.
Any custom code that moves things should ask the browser first:
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)');
function setup() {
if (reduce.matches) return; // leave everything in its final position
// start the parallax, the cursor follower, the GSAP timeline
}
setup();
reduce.addEventListener('change', setup);If your custom code uses GSAP, gsap.matchMedia() accepts the same media query and reverts the animations it created when the query stops matching.
What Webflow handles for you
Webflow Interactions, the GSAP-based version, now have reduced-motion settings on each interaction. For an entrance whose start state is hidden, pick the option that lands the element in its final state, “skip to end”. Any option that leaves the element at its start state leaves it invisible.
Webflow’s native smooth scroll to anchors already respects the preference, so the page jumps instead of gliding. Everything else is yours: custom CSS keyframes, embeds, Lottie files and third-party scripts.
WCAG 2.3.3 Animation from Interactions (level AAA) is the criterion behind all of this: motion triggered by scrolling or clicking should be possible to turn off, unless the motion itself carries the meaning.
How to test it in two minutes
- In Chrome DevTools, open the Rendering panel and set “Emulate CSS media feature prefers-reduced-motion” to
reduce. Or turn on Reduce motion in your operating system’s accessibility settings. - Reload each page with a staggered entrance and watch the first second. Every block should be visible on the first frame. A blank moment means a delay survived.
- Wait ten seconds. Anything still moving is a loop the rule did not stop, or an inline transform.
- Scroll the page. Parallax and scroll-linked effects should stay still.
- Click an anchor link. The page should jump, not glide.
Motion is part of how we build sites at Blago, and so is the off switch. If you want both done properly on your Webflow site, see our motion design, video and 3D work or tell us about the project.