My site’s moved CMS and servers. If you spot a problem, let me know.

Stuff & Nonsense product and website design

How I fixed my Reduced Motion Broke My Layout problem

It’s incredibly important to respect people’s preferences and to ensure that any movement is turned off when they’ve set “reduced motion” in their OS settings. After adding my Magnificent 7 animations yesterday, I went back to check them with reduced motion enabled. Oh hell, my CSS grid has also stopped working, and it took me all morning to realise the issue wasn’t the grid, but how I’d structured my media queries.

I’d used this boilerplate CSS:

@media screen and (prefers-reduced-motion: reduce) {
html {
scroll-behaviour: auto;
animation-duration: 1ms !important;
animation-iteration-count: 1 !important;
transition-duration: 1ms !important; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation: none !important;
transition: none !important; }
}

That looked fine until I noticed that when reduced motion was selected, grid layouts weren’t applied. They didn’t even appear in DevTools. It was like my whole layout was trapped inside a media query it shouldn’t be in.

Where it all went wrong

1. Two separate prefers-reduced-motion blocks

I’d written two different queries—one with screen and one without. Turns out that browsers treated them as separate layers in the cascade. Sometimes they combined, sometimes they didn’t, depending on their position in the file.

That made it possible for reduced-motion rules to override layout ones. In DevTools, it even looked like my @media (min-width:64em) rules were nested inside reduced motion, even though technically they weren’t.

2. The reduced-motion block came after my layout queries

Later in the file, I had a @media (prefers-reduced-motion: reduce) block sitting below my layout breakpoints. That meant when reduced motion was enabled, it took priority over my grid display rules:

@media (min-width: 64em) {
[role="banner"] {
display: grid;
grid-template-columns: var(--grid-compound); }
}

Even though my motion reset didn’t touch layout properties, the browser’s cascade flattened them together, and the result was no grid.

3. My animation reset wasn’t truly global

I’d disabled transitions on *, but only changed scroll behaviour on html:

html { scroll-behavior: auto; }
*, *::before, *::after {
  animation: none !important;
  transition: none !important; }

That meant nested containers—like scrollable divs or SVGs—could still animate or scroll smoothly. So even though the top of the CSS respected reduced motion, some other sections didn’t.

4. My motion reset didn’t really stop animations

Setting an animation’s duration to 1ms makes it very, very short, but it’s not the same as disabling it altogether. It still fires, just instantly. That can trigger layout reflows, flashes, or elements appearing mid-animation.

5. Layout transforms were tied to those animations

Some layout elements use transforms inside animations. When reduced motion shortened those animations to 1ms, the transform started and ended before the layout had fully rendered. That left my grid invisible until a resize or refresh.

The fix: isolate motion resets

Although it took a while to figure out, the solution turned out to be pretty simple—move all motion resets to a single, self-contained section near the top of the stylesheet.

/* REDUCE MOTION GLOBALLY */
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto !important; }
*, *::before, *::after {
animation: none !important;
transition: none !important;
scroll-behavior: auto !important; }
}
@media (prefers-reduced-motion: no-preference) {
html { scroll-behavior: smooth; }
}

That was it. No more layout interference.

Why it works

By isolating motion resets early in the cascade, I:

So, now I think of my stylesheets in “layers”:

  1. Global styles
  2. Reduced motion reset
  3. Layout media queries
  4. Components and animations

That way, the reduced-motion section never affects my layout. Here’s the pattern I’ll follow from now on:

  1. Put reduced-motion reset near the top
  2. Keep it separate from grid or breakpoint media queries
  3. Never mix layout and motion in the same block

That way, my designs will respect accessibility settings without breaking the layout as they’ve done before.


October 15, 2025 • Andy Clarke • css

You might also like

Shop

Eleventy in a Box

A premium Eleventy starter kit for designers and developers who want to spend less time setting up the same project structure and more time designing distinctive websites.

Shop

Layout ❤︎

Free compound grid and modular grid layout generators, plus a set of HTML/CSS layout templates you can call on to make more interesting layouts, available to buy.