WCAG 2.3.1: Three Flashes or Below Threshold
Most accessibility failures make a page harder to use. This one can put someone in the hospital. Flashing content can trigger seizures in people with photosensitive epilepsy, so WCAG draws a hard line: nothing on the page may flash more than three times in any one second — unless the flash is small and dim enough to fall below the general flash and red flash thresholds.
The success criterion, in full
Web pages do not contain anything that flashes more than three times in any one second period, or the flash is below the general flash and red flash thresholds.
Note the scope: anything on the page. Unlike most criteria, 2.3.1 explicitly applies to all content on the page — your own animations, embedded videos, animated GIFs, ads, and third-party widgets — because dangerous flashing anywhere can prevent a user from using the page at all.
Who this protects and why
Photosensitive epilepsy affects roughly 1 in 4,000 people. For them, flashing light in the range of about 3 to 60 flashes per second can trigger a seizure — with peak sensitivity between 15 and 20 flashes per second. The trigger is not gradual: a single exposure of less than a second can be enough. The most infamous real-world case, a 1997 Pokémon broadcast with rapid red-blue flashing, sent hundreds of viewers to hospital.
The risk is not limited to epilepsy. Rapid flashing and strobing can trigger migraines, dizziness, disorientation, and nausea in people with vestibular disorders and general photosensitivity. And unlike a missing alt attribute, a user cannot “work around” dangerous flashing — by the time they perceive it, the exposure has already happened.
People with photosensitive epilepsy
Flashing between 3–60 Hz, especially saturated red, can trigger seizures on first exposure with no warning.
People with vestibular disorders
Strobing and rapid luminance changes cause dizziness, nausea, and disorientation even without a seizure.
People with migraine
Flicker is a well-documented migraine trigger; a flashing banner can end someone's workday.
Everyone else
Fast flashing is distracting and unpleasant for all users — removing it is a pure usability win.
The two thresholds, explained
The criterion has two branches. The simple branch: three flashes or fewer in any one-second period is always acceptable. The nuanced branch: flashing faster than that is still permitted only if it stays below both the general flash threshold and the red flash threshold — definitions borrowed from broadcast safety standards and adapted for screens viewed at close range.
General flash threshold
A general flash is a pair of opposing changes in relative luminance of 10% or more of the maximum relative luminance, where the relative luminance of the darker image is below 0.80. In plain terms: a strong bright-dark-bright (or dark-bright-dark) pulse. Fast flashing stays below the threshold — and passes — when the combined flashing area is small enough: no more than about 25% of any 10-degree visual field (0.006 steradians). At a typical viewing distance that works out to roughly a 341 × 256 CSS-pixel region — anything larger flashing quickly is a failure.
Red flash threshold
A red flash is any pair of opposing transitions involving a saturated red. Saturated red is disproportionately provocative for photosensitive seizures — transitions to and from strong red are dangerous even when the overall luminance change would pass the general threshold. If your flashing involves saturated red, treat any rate above three per second as a failure regardless of size or brightness.
The practical takeaway: you do not need to memorize the steradian math. If nothing on your page flashes more than three times per second, you pass automatically. Reserve the threshold analysis for edge cases like small status indicators, and use a tool — not your eyes — for that analysis.
Why there is no flashing demo here
We deliberately do not reproduce dangerous flashing on this page. A live demonstration of seizure-inducing content would put the very people this criterion protects at risk — even a “brief, educational” strobe can trigger a seizure on first exposure, and a warning dialog is no protection for a user who arrives via an in-page anchor or has the page read aloud. Describing the failure is enough; experiencing it should never be required.
Here is what the dangerous pattern looks like, in words. Imagine a large panel — most of the content area — alternating between pure white and saturated red five times every second. Each white-to-red-to-white cycle is a pair of opposing transitions involving saturated red (a red flash) and a luminance swing far beyond 10% (a general flash). At five flashes per second, over an area far larger than 25% of a 10-degree visual field, it fails both branches of 2.3.1 simultaneously — and sits close to the most seizure-provocative frequency band.
A safe version of the same attention-getting effect: a gentle pulse between white and a pale tint at two cycles per second, in a small region, with a visible control to stop it. Better still, use a non-flashing affordance — a border highlight, a badge, or a single fade-in — which draws the eye without any flash at all.
Pass and fail examples
Passes 2.3.1
- A notification badge that pulses gently twice per second with a subtle color change.
- A recording indicator blinking once per second (1 Hz).
- A cursor caret or loading spinner — continuous motion, not opposing luminance flashes.
- A tiny status LED-style dot flashing at 4 Hz whose area is far below the general flash threshold and involves no saturated red.
- Video content screened with PEAT and confirmed below both thresholds.
Fails 2.3.1
- A full-width “SALE!” banner strobing between white and red five times per second.
- An animated GIF of lightning or camera flashes cycling faster than 3 Hz over a large area.
- An embedded video containing strobe effects, rapid scene cuts, or gunfire flashes above the thresholds.
- A third-party ad that flashes rapidly — you are responsible for everything rendered on your page.
- A CSS animation toggling a large element’s background between dark and light every 100–200ms.
Code examples
CSS animation: strobe vs. gentle pulse
The failing version flashes a large area between high-contrast colors ten times per second. The passing version pulses a subtle tint at 2 Hz and respects the user’s reduced-motion preference.
/* ✗ Fails: 10 flashes/second, large area, high contrast */
.alert-banner {
animation: strobe 0.1s infinite alternate;
}
@keyframes strobe {
from { background: #ffffff; }
to { background: #ff0000; } /* saturated red — red flash */
}
/* ✓ Passes: 2 cycles/second, subtle luminance change */
.alert-banner {
animation: gentle-pulse 0.5s infinite alternate;
}
@keyframes gentle-pulse {
from { background: #ffffff; }
to { background: #e3f2fd; } /* well under 10% luminance swing */
}
/* ✓ Better: honor the user's motion preference */
@media (prefers-reduced-motion: reduce) {
.alert-banner { animation: none; }
}JavaScript: guard the flash rate and give users a stop control
If an effect must blink, clamp the rate in code so no future change can accidentally exceed three flashes per second, cap the duration, and always render a stop control (which also helps you meet 2.2.2 Pause, Stop, Hide).
// ✗ Fails: 5 flashes per second, no way to stop it
setInterval(() => el.classList.toggle("flash"), 200);
// ✓ Passes: rate clamped to ≤ 3 Hz, auto-stops, user-stoppable
const MAX_FLASHES_PER_SECOND = 3;
const SAFE_INTERVAL_MS = Math.ceil(1000 / MAX_FLASHES_PER_SECOND); // 334ms
function startBlink(el, { durationMs = 3000 } = {}) {
const timer = setInterval(() => el.classList.toggle("blink"), SAFE_INTERVAL_MS);
const stop = () => {
clearInterval(timer);
el.classList.remove("blink");
};
setTimeout(stop, durationMs); // never blink indefinitely
return stop; // wire this to a visible Stop button
}
const stopBlink = startBlink(document.getElementById("status"));
document.getElementById("stop-btn").addEventListener("click", stopBlink);Video and GIF content: screen it, warn, and never autoplay
Flashing most often ships inside media, not CSS. Screen every video with PEAT before publishing. If flashing content is unavoidable and below the thresholds, still warn users and keep it behind an explicit play action.
<!-- ✗ Fails: autoplaying video with unscreened strobe effects -->
<video src="/promo-strobe.mp4" autoplay loop muted></video>
<!-- ✓ Passes: screened with PEAT, no autoplay, content warning -->
<p id="flash-warning">
<strong>Content note:</strong> this video contains brief flashing
imagery (verified below WCAG 2.3.1 thresholds with PEAT).
</p>
<video
src="/promo-screened.mp4"
controls
preload="metadata"
aria-describedby="flash-warning">
</video>Common failures
- Attention-grabbing banners or CTAs that strobe between high-contrast colors faster than three times per second.
- Animated GIFs — lightning, sparkles, glitch effects, camera flashes — embedded without checking their frame rate and luminance swings.
- Embedded or user-uploaded video containing strobe lighting, rapid cuts, or muzzle flashes that was never screened with PEAT.
- Third-party ads and widgets that flash: 2.3.1 applies to the whole page, so their failure is your failure.
- Saturated red used in any fast blink — red flashes fail at rates and sizes where other colors might squeak under the general threshold.
- JavaScript 'blink' effects driven by setInterval with periods under ~334ms and no rate guard, so a later tweak silently makes them dangerous.
- Relying on a warning dialog instead of removing the flashing — a warning does not make above-threshold flashing conform, and users can land past it.
- Assuming small-area safety without measuring: the exception is a precise area/luminance calculation, not a feeling that the element 'looks small'.
How to test for 2.3.1
Important: never test by deliberately watching suspect content. Analyze recordings and code instead — that is exactly what the tooling is for.
- 1
Inventory everything that moves or blinks
List every animation, video, GIF, ad slot, and embedded widget on the page. 2.3.1 applies to all content on the page, so third-party material is in scope too.
- 2
Run PEAT on video and screen recordings
The free Photosensitive Epilepsy Analysis Tool (PEAT) from the Trace Research & Development Center implements the general flash and red flash threshold calculations. Record the page or export the video, run it through PEAT, and treat any warning as a blocker.
- 3
Audit animation code for rate
Search CSS for animation durations under ~334ms with 'infinite' iteration, and JavaScript for setInterval/setTimeout loops with periods under 334ms that toggle visual state. Any large luminance change driven at that rate is a likely failure.
- 4
Check for saturated red transitions
Wherever flashing exists at any rate above 3 Hz, check whether either state is a saturated red. If so, it must be removed or slowed — the red flash threshold is much stricter than the general one.
- 5
Verify area against the small-safe-area exception
If fast flashing must remain, confirm the combined flashing area is under roughly 25% of a 10-degree visual field (about 341 x 256 CSS pixels at typical viewing distance) and the luminance swing is under 10%. Document the measurement.
- 6
Confirm users can stop residual blinking
Any blinking that remains should stop automatically within a bounded time or offer a visible pause/stop control — this overlaps with 2.2.2 Pause, Stop, Hide and is good defense in depth.
Track this criterion alongside the rest of your audit in the WCAG 2.2 checklist.
Frequently asked questions
What does WCAG 2.3.1 Three Flashes or Below Threshold require?
It requires that web pages do 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. It is a Level A criterion under Guideline 2.3 Seizures and Physical Reactions, and it applies to the whole page: because flashing content can prevent a user from using the entire page at all, every piece of content on the page must satisfy it — including ads, embedded videos, animated GIFs, and third-party widgets.
What are the general flash and red flash thresholds?
A 'general flash' is a pair of opposing changes in relative luminance of 10% or more of the maximum relative luminance, where the darker state is below 0.80 relative luminance. A 'red flash' is any pair of opposing transitions involving a saturated red. Flashing that stays above three flashes per second is still permitted if it is below both thresholds — in practice, if the flashing area is small enough (the combined flashing area occupies no more than about 25% of any 10-degree visual field, roughly a 341 x 256 pixel block at typical viewing distance) or the luminance/color change is too subtle to be dangerous.
Who is at risk from flashing content?
People with photosensitive epilepsy, which affects roughly 1 in 4,000 people, can experience seizures triggered by flashing between about 3 Hz and 60 Hz, with peak sensitivity between 15 and 20 flashes per second. Saturated red flashing is especially provocative. Beyond epilepsy, rapid flashing can also trigger migraines, dizziness, and nausea in people with vestibular disorders or photosensitivity that never rises to the level of a seizure. A single exposure can cause a seizure — this is one of the few WCAG criteria where a failure can cause direct physical harm.
Is three flashes per second always safe?
Three or fewer flashes per second keeps you within the letter of 2.3.1, but the guidance is deliberately conservative rather than a target to design toward. The Understanding document notes the threshold was set based on broadcast standards adapted for computer screens viewed at close range. Best practice is to avoid flashing entirely, keep any unavoidable flashing well under the limits, avoid saturated red, keep the flashing area small, and give users a way to stop or pause the effect (which also supports 2.2.2 Pause, Stop, Hide).
How is 2.3.1 different from 2.3.2 Three Flashes?
2.3.1 (Level A) permits flashing above three per second only when it stays below the general flash and red flash thresholds — small or low-contrast flashing can pass. 2.3.2 Three Flashes (Level AAA) removes that allowance entirely: nothing on the page may flash more than three times in any one-second period, regardless of size, luminance, or color. If you simply avoid all fast flashing you satisfy both at once. 2.3.3 Animation from Interactions (AAA) is related but covers motion animation, not flashing.
How do I test content against WCAG 2.3.1?
Use PEAT (the Photosensitive Epilepsy Analysis Tool, from the Trace Research Center) to analyze video and screen-capture recordings of animated content — it implements the general and red flash threshold math for you. For code, audit CSS animations and JavaScript timers: any interval faster than about 333ms driving a large luminance change is suspect. Review video, GIF, ad, and third-party content before publishing, since 2.3.1 applies to everything on the page. Never test by staring at suspect content yourself — analyze recordings with tooling instead.
Related Success Criteria
Web pages do not contain anything that flashes more than three times per second.
Motion animation triggered by interaction can be disabled.
All functionality is available from a keyboard interface.
Focus can be moved away from any component using standard keyboard methods.
All functionality is available from a keyboard interface without exception.