Flashing Content and Seizure Thresholds

Most animation accessibility advice is about comfort: motion that distracts, dizzies or annoys. Flashing is different. Content that flashes at certain frequencies and intensities can trigger seizures in people with photosensitive epilepsy, and the harm is immediate and severe. That is why WCAG treats it as a Level A requirement — the most basic tier — and why it applies whether or not a user has expressed any preference. CSS makes flashing trivially easy to create by accident: an infinite alternate animation on a background colour with a short duration, a blinking error border, a "strobe" effect on a sale banner. This page explains what counts as a flash, the thresholds, and patterns that draw attention without approaching them. It belongs to Accessibility in CSS Animations in the CSS-Only Micro-Interactions & Animations guide.

What WCAG requires

Success criterion 2.3.1, Three Flashes or Below Threshold, says web pages must not contain anything that flashes more than three times in any one-second period, unless the flash is below the general flash and red flash thresholds. The AAA criterion 2.3.2, Three Flashes, removes the threshold exception: nothing may flash more than three times per second at all.

A flash is a pair of opposing changes in relative luminance — bright to dark and back — where the darker state is dark enough and the change is large enough. Specifically, the general flash threshold is crossed when the change is 10% or more of maximum relative luminance, the darker image is below 0.80 relative luminance, and the flashing area together is larger than roughly a quarter of a 10-degree visual field (the guidelines approximate this as 341 by 256 pixels at typical viewing distances on a 1024 by 768 screen). The red flash threshold covers transitions to or from saturated red, which is especially provocative.

Counting flashes in one second Two luminance traces across a one-second window. The top trace rises and falls twice, a slow pulse that stays within three flashes per second and passes. The bottom trace alternates six times in the same window, like an 83 millisecond alternate animation, and fails because it exceeds three flashes per second. Any one-second window, at most three flashes pass fail slow pulse, 2 cycles hard alternation, 6 flashes 0 s 1 s

Measuring exact luminance and area by hand is impractical, which is why teams usually adopt a simpler rule that stays well clear: no more than three luminance reversals per second, ever, and avoid large, high-contrast alternation entirely. Tools such as the Photosensitive Epilepsy Analysis Tool (PEAT) analyse recorded video when a precise assessment is required.

Translating the rule into CSS durations

For an alternate animation, each iteration is one change. A full flash is two changes — bright to dark and back — so an animation alternating every 166 milliseconds produces three flashes per second. That makes the arithmetic:

  • animation: blink 166ms steps(1) infinite alternate — right at the limit. Never do this with high-contrast content.
  • animation: blink 500ms ease-in-out infinite alternate — one flash per second, with soft transitions rather than hard cuts.
  • animation: blink 1s ease-in-out infinite alternate — one flash every two seconds.

Easing matters as much as frequency. A steps(1) or step-end timing produces instant cuts between states, the most intense kind of flash. A smooth ease-in-out spreads the luminance change over the whole duration, which is gentler even at the same rate.

The complete implementation

An attention cue that stays far below every threshold: a slow, low-contrast pulse on a notification badge, limited to a few iterations, plus a static alternative. Compare it with the demo's "don't" example, which is rendered safely here as a static description rather than an actual strobe.

Live demoAn attention cue that stays below flash thresholds
Hover the panel to replay. The badge pulses twice with a slow scale and fading ring, never flipping between light and dark. The "don't" pattern is described, not shown.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Safe attention pulse</title>
<style>
  body { font: 15px/1.5 system-ui, sans-serif; margin: 2rem; }

  .badge {
    display: inline-grid;
    place-items: center;
    min-inline-size: 1.5rem;
    block-size: 1.5rem;
    padding-inline: 0.4rem;
    border-radius: 999px;
    background: #2563eb;
    color: #fff;
    font-size: 0.8rem;
    font-weight: 700;
  }

  .badge--new {
    /* 1.2s per half-cycle: well under one flash per second.
       Scale and a soft ring, not a luminance flip. */
    animation: attention 1.2s ease-in-out 4 alternate both;  /* even count: ends at rest */
  }

  @keyframes attention {
    from { box-shadow: 0 0 0 0 rgb(37 99 235 / 0.45); scale: 1; }
    to   { box-shadow: 0 0 0 6px rgb(37 99 235 / 0); scale: 1.08; }
  }

  @media (prefers-reduced-motion: reduce) {
    .badge--new {
      animation: none;
      outline: 2px solid #1d4ed8;   /* a static cue */
      outline-offset: 2px;
    }
  }
</style>
</head>
<body>
  <p>Inbox <span class="badge badge--new">3</span></p>
</body>
</html>

Three choices keep this safe. The pulse changes size and a translucent ring rather than flipping the badge between light and dark, so the luminance change is small. The duration is long — 1.2 seconds per direction — so the rate is far under one cycle per second. And the iteration count is 4 — two full pulses — so the animation stops after about five seconds instead of running forever. An even count with alternate also ends on the from keyframe, so the badge settles back at its normal size rather than staying enlarged.

The key technique: animate shape and position, not luminance

The safest attention cues avoid large luminance swings altogether. Movement, scale, and a change in an outline or border draw the eye without the rapid light-dark alternation that defines a flash.

Risky cues versus safer cues Left column lists risky cues: a background alternating between white and black, blinking text, and a strobing red border. Right column lists safer cues: a slow scale pulse, a fading ring that expands outward, and a one-time slide-in with no repetition. The safer cues change shape or position rather than overall brightness. Change shape, not brightness Risky Safer background black ↔ white blinking text (steps) strobing saturated red slow scale pulse fading ring, finite count one-time slide-in Low contrast, slow and finite beats bright, fast and infinite.

Red deserves special mention. Saturated red flashing is more likely to provoke seizures than other colours at the same luminance change, which is why it has its own threshold. Error states are the usual place designers reach for a red blink. A red border that appears and stays, with an icon and a message, communicates the error better than a blinking one and carries no risk.

Audit patterns that slip through

Flashing rarely comes from a deliberate strobe. More often it emerges from ordinary code:

  • Rapid state toggles. A hover effect that inverts a large card's colours, on a grid where moving the mouse crosses several cards per second, produces a sequence of flashes across the page.
  • Loading shimmers with high contrast. A skeleton shimmer that sweeps a bright band across a dark surface quickly can approach flash territory when many skeletons animate in sync over a large area.
  • Video and GIF backgrounds. CSS cannot inspect media content. Autoplaying backgrounds need review of the media itself, and a pause control, as described in Pause Controls for Looping Animations.
  • Theme switches. Toggling from a dark to a light theme swaps luminance across the entire viewport. Once is fine; a toggle that can be spammed, or an automatic theme flip on scroll, is not.

Designing sale banners and alerts without strobing

Marketing requests for "something that really grabs attention" are the most common source of dangerous flashing. Offer alternatives that deliver the goal. A banner can slide in once from the top and stay; a countdown can tick with numbers changing in place, which changes a small area of text rather than a large block of luminance; a price can be emphasised with a static colour block and size rather than a blinking background. If a repeating effect is truly required, cap it: a slow shimmer that runs once per page view, or a pulse with a finite iteration count, keeps attention without continuous stimulation. These choices also satisfy WCAG 2.2.2, which requires a way to pause any movement lasting more than five seconds.

Reduced motion is an extra layer, not the fix

It is tempting to wrap risky animations in @media (prefers-reduced-motion: no-preference) and consider the job done. That is not sufficient. Many people with photosensitive epilepsy have never changed that operating system setting, and some do not know they are photosensitive until a seizure occurs. WCAG 2.3.1 applies to every user regardless of preferences. Keep flashing below the thresholds for everyone, and then use the reduced-motion query to remove remaining non-essential motion for people who asked for less. WCAG Motion Success Criteria sets the criteria side by side.

Browser support

Everything on this page uses long-established features: @keyframes is supported in Chrome 43+, Edge 12+, Firefox 16+ and Safari 9+, and prefers-reduced-motion in Chrome 74+, Edge 79+, Firefox 63+ and Safari 10.1+. The standalone scale property used in the implementation is supported in the same versions as translate: Chrome and Edge 104+, Firefox 72+ and Safari 14.1+.

FAQ

What is the three flashes rule? WCAG 2.3.1 requires that nothing flashes more than three times in any one-second period, unless the flashing is below the general and red flash thresholds. Staying at or under three flashes per second is the simplest way to comply.

What counts as a flash in CSS? A pair of opposing changes in relative luminance large enough to cross the threshold, such as a bright element turning dark and back. Blinking, strobing borders, alternating backgrounds and fast opacity toggles on high-contrast content can all be flashes.

Is a small flashing element safe? Area matters: flashing that covers only a small part of the screen can fall below the general flash threshold. But viewing distance and screen size vary, so area alone is a weak safeguard. Slow, low-contrast motion is safer than relying on small size.

Does prefers-reduced-motion cover flashing? Not reliably. Photosensitive users may not have set it, and WCAG's flash requirement applies regardless of preferences. Flashing above the thresholds must be avoided for everyone; reduced motion is an extra layer, not the fix.

Related articles

More pages in the same section.