# Badges and icons that blink more than three times a second

Source: https://easeweb.dev/learn/fast-blinking
Topics: Time limits and motion > Nothing flashes more than three times a second (WCAG 2.3.2)
The fix: Either keep the dot still and let the word "Live" carry the meaning, or slow the blink to a soft pulse of one flash every two seconds that stops after two.
Test with: flash analysis, reduced motion
References: https://www.w3.org/WAI/WCAG22/Understanding/three-flashes.html https://www.w3.org/WAI/WCAG22/Techniques/general/G19 https://www.w3.org/WAI/WCAG22/Understanding/three-flashes-or-below-threshold.html https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html https://epilepsysociety.org.uk/about-epilepsy/epileptic-seizures/seizure-triggers/photosensitive-epilepsy

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

## What happens

A clothing shop streams live try-on sessions, and its home page shows a card for the stream that is on now: a picture, the title "Autumn coats: try-on and Q&A", and in the corner a "Live" badge with a small red dot. To show the stream is live, the dot blinks: red, then white, so it vanishes against the badge, and back, four times a second, for as long as the page is open. The same fast blink turns up as an unread-message dot, a recording light in a video call, a "New" label, a bell icon that flickers when a notification arrives, a typewriter cursor drawn in CSS, and a "glitch" effect that makes a word flicker.

## Why it fails

Success criterion 2.3.2 Three Flashes, at Level AAA, allows nothing on the page to flash more than three times in any one second. Unlike 2.3.1, it has no exception for flashes that are small or dim: Understanding 2.3.2 says it doesn't allow any flashing at a frequency greater than three a second, and that even a single flashing pixel would fail. The dot passes 2.3.1. At 10 × 10 pixels it covers about 0.1% of the 341 × 256 pixel field that 2.3.1 measures against, far under the quarter it allows. But every swap from red to white and back is a flash, both a general flash and a red flash, and it happens four times a second, so it fails 2.3.2. Because it blinks without end beside other content, it also fails 2.2.2 Pause, Stop, Hide at Level A.

## Who is affected

Live shopping streams are watched for many minutes at a time, so the dot stays in view for the whole session, close to the title and the products people are reading about. Level AAA is rarely required in full, but this part of it costs one line of CSS to meet.

## What automation and AI miss

The audit counts flashes at any size: it steps every CSS and Web Animations API animation through its first seconds, watches for scripts that swap a class on a timer, and reports anything that flashes more than three times in a second as a 2.3.2 finding, with its rate and colours. Size-based checks, including the audit's own 2.3.1 check, pass a small dot by design, so only counting finds it. The audit doesn't look inside frames from other sites, such as a third-party video player or chat widget, or inside video, animated GIFs and canvas. AI tools tend to treat a small blink as harmless decoration, and "live dot" and "notification ping" snippets online often use cycles of a quarter or half a second.

## Before: a dot that blinks four times a second

```html
<span class="live-badge"><span class="live-dot"></span>Live</span>
```

```css
.live-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.125rem 0.5rem;
  border-radius: 0.25rem;
  background: #fff;
  color: #111;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
}
.live-dot {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 50%;
  background: #e00000;
  animation: blink 0.25s steps(1) infinite;
}
@keyframes blink {
  50% { background: #fff; }
}
```

The dot jumps from red to white and back every quarter of a second, so it flashes four times a second, and never stops.

## After: a still dot

```css
.live-dot {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 50%;
  background: #e00000;
}
```

The dot stays red and nothing flashes. The word "Live", which was always in the badge, says the stream is live, and the red dot still marks it at a glance. There is nothing to count and nothing to stop, so it passes 2.3.2, 2.3.1 and 2.2.2.

## After: a slow pulse that stops

```css
.live-dot {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 50%;
  background: #e00000;
}
/* One soft pulse every two seconds, twice: four seconds, then still. */
@media (prefers-reduced-motion: no-preference) {
  .live-dot { animation: live-pulse 2s ease-in-out 2; }
}
@keyframes live-pulse {
  50% { opacity: 0.4; }
}
```

The dot fades to 40% and back over two seconds, twice, then stays red. Each flash takes two seconds, so no second holds more than one, and the pulse is over in four seconds, which also meets 2.2.2. The fade keeps the change soft. Its speed is what passes, though: a fade that ran four times a second would still be four flashes. It is written inside `no-preference` because it costs nothing and spares people who have asked for less motion.

## Which option to use

Both pass 2.3.2, 2.3.1 and 2.2.2. The still dot needs no measuring and nothing can make it fail later; it gives up the motion, and the word "Live" carries the meaning, as it already did. The slow pulse keeps a sign of life as the page opens, at a rate well clear of the flashing that sets off seizures, in a few lines of CSS; choose it when the design wants the dot to move. Neither can keep moving for the whole stream: that would need a Pause button under 2.2.2, and a status that stays true for an hour doesn't need to move to be seen.

## Implementation decisions

A fade is a flash too. A flash is a change in brightness there and back, whether it jumps with `steps()` or eases, so the timing that matters is the length of each cycle, not its curve. With `animation-direction: alternate`, each cycle is only half a flash: `0.25s alternate` flashes twice a second, and `0.125s alternate` four times.

Fast blinks hide in small parts of a page that nobody thinks of as flashing. Each needs the same fix, still or a second or more per flash:

- Unread and notification dots: a still dot with the count in text, or one slow pulse when something new arrives.
- Recording and "on air" lights in video tools: still red, with the word beside it.
- Cursors drawn in CSS for a typing effect: a second or more per blink, and stop when the typing does.
- "Glitch" effects that make a word flicker: a single change, or none.
- Loading dots that light up in turn: keep each dot's cycle at a second or longer, and stop them when loading ends.

Red counts on its own. A change to or from a saturated red is a red flash even when the brightness barely changes, so swapping the white for a grey of the same brightness doesn't help.

Players, chat widgets and ad slots embedded from other sites bring their own indicators, and the page is responsible for them. Check them by hand, and use their settings to turn the blinking off where they offer one.

A large area that flashes is a Level A failure with a stricter cost: see [flashing banners and videos that can trigger seizures](/learn/flashing-content). A pulse or glow that never ends, at any speed, is covered in [pulsing buttons, glowing badges and animations that never stop](/learn/endless-animations).

## Verify the fix

1. Find everything that blinks, pulses or flickers, at any size: badges, dots, icons, cursors and loading indicators, including inside embedded players and widgets.
2. Count the flashes in each one's busiest second, with the browser's Animations panel slowed to 10% or a screen recording stepped frame by frame: three or fewer.
3. Load the page and wait five seconds without touching anything: every blink or pulse that started by itself has stopped.
4. Turn on Reduce motion, or pause the Animations panel, and read each badge with nothing moving: its meaning is still clear from its text.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the design system, the icon set or an embedded widget changes.

## Limits

This is a starting pattern, not a guarantee for every application, and not medical advice. Meeting 2.3.2 lowers the risk further than 2.3.1 does, but some people react to slower flicker too. The audit counts flashes it can read from the page's own document, not inside frames from other sites, video, animated images or canvas; those still need a person and a flash analysis tool.
