HTML has no tag that makes text blink any more. The old <blink> element does nothing in today’s browsers, and neither does text-decoration: blink. What works is a three-line CSS animation, and you can copy it from the next section. Give it a blink count so it stops by itself: text that blinks forever is the version that breaks the accessibility rules.
The copy-paste blinking text code
<p class="blink">Sale ends at midnight</p>.blink {
animation: blink 1s step-end 4; /* 1s per blink, 4 blinks, then it stops */
}
@keyframes blink {
50% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.blink { animation: none; }
}That’s a hard blink, the same on and off switch the old tag produced. step-end is what makes it switch: the text holds at full opacity for the first half of each second, jumps to invisible for the second half, and jumps back. The 4 is how many times it does that. After the fourth blink the animation is over and the text stays on screen, because the keyframes only say what happens at the halfway point and the element’s own opacity (fully visible) is where it starts and ends.
Change the speed with the 1s and the number of blinks with the 4. The class goes on any element: a heading, a link, a table cell.
A softer fade
Swap step-end for an easing curve and the text fades down and back up:
.pulse {
animation: pulse 1.5s ease-in-out 3;
}
@keyframes pulse {
50% { opacity: 0.25; }
}
@media (prefers-reduced-motion: reduce) {
.pulse { animation: none; }
}I stop the fade at 0.25 and don’t take it to zero. The dip is still obvious, and the words stay readable the whole time, which a hard blink can’t offer: for half of every second there is nothing to read. On a page people are meant to read and not just glance at, this is the one I’d use.
Blinking one word in a sentence
Wrap the words in a span and use the same class:
<p>Doors open at <span class="blink">7 pm sharp</span>, not 8.</p>The rest of the sentence holds still because opacity hides the text without removing its box. That isn’t true of every way to hide something. If you blink by switching display: none on and off, which some older scripts do, the hidden words give up their space and everything after them slides left, then snaps back. In my test the “not 8.” after the blinking words jumped 115 pixels sideways on every blink.
visibility: hidden keeps the layout steady too, and one generator that ranks for this search uses it. I’d still pick opacity. When I paused both versions in their hidden phase and looked at Chrome’s accessibility tree, the opacity text was still listed and the visibility text was gone, so a screen reader that arrives at the wrong moment has nothing to read.
Why the blink tag does nothing
MDN now files <blink> under its glossary as “an obsolete HTML feature no longer supported by web browsers”, and adds that it “was never properly specified and never achieved significant cross-browser support”. It came from early Netscape Navigator. Firefox still had it until 2013, and Mozilla’s release notes for Firefox 23 (August 6, 2013) record the end: “Dropped blink effect from text-decoration: blink; and completely removed <blink> element”.
Type the tag into a page today and you get plain text. Chrome 156 treats it as an unknown element, like a tag you made up. Several tutorials near the top of Google haven’t caught up: one still says some browsers support it, and a forum thread from 2002 that still ranks for this search offers <blink> and text-decoration: blink as the answer.
The CSS property is the sneakier of the two, because text-decoration: blink is still valid CSS. blink remains in the specification for text-decoration-line, with the note that browsers may choose not to blink the text and that the value is deprecated in favour of CSS animations. MDN’s compatibility data says of Chrome and Firefox that the value “does not have any effect”. So nothing warns you. Chrome accepted the declaration when I tried it, reported it back as the computed style, and the text sat there without blinking. If you’ve inherited a stylesheet with text-decoration: blink in it, delete the line and use the animation above.
Stopping after a set number of blinks
The number at the end of the animation shorthand is the iteration count, and the total running time is duration times count. Keep that at five seconds or under: 1s × 4, 0.8s × 6 and 1.5s × 3 all fit. Five seconds is the line WCAG draws (the exact wording is in the next section) and it’s a sensible limit anyway. Four blinks is enough to get the line noticed, and after that it only gets in the way of reading the rest of the page.
Two things go wrong when people write their own keyframes. Add forwards to an animation whose last keyframe is opacity: 0 and the text finishes its last blink and never comes back. I ran that version and the paragraph was blank from the fourth second on. The 50% keyframe above can’t end that way. The other is the JavaScript route. Most of the setInterval snippets printed on tutorial pages toggle the text forever and never clear the timer, so you write more code and get a worse result than one CSS line that counts for you. I wouldn’t use a script for this at all.
If it really has to blink forever
A “Live now” badge is the usual case. Set the count to infinite and put a control next to it that turns the blinking off:
<p>
<span class="blink live" id="live">Live now</span>
<button type="button" id="stop-blink">Stop blinking</button>
</p>.live {
animation-iteration-count: infinite;
}document.getElementById("stop-blink").addEventListener("click", () => {
document.getElementById("live").style.animation = "none";
});The button removes the animation and doesn’t pause it, on purpose. animation-play-state: paused freezes the text wherever it happens to be, and half the time that’s the invisible half. I paused one mid-blink and the label simply vanished. Pausing on hover isn’t a fix either: W3C’s notes on the rule say an animation that stops only while the user’s focus is on it doesn’t count as a way to pause.
The accessibility rules that apply
Two WCAG success criteria cover blinking text, and both are Level A, the baseline level.
Success Criterion 2.2.2, Pause, Stop, Hide, is about distraction. Its text: “For any moving, blinking or scrolling information that (1) starts automatically, (2) lasts more than five seconds, and (3) is presented in parallel with other content, there is a mechanism for the user to pause, stop, or hide it unless the movement, blinking, or scrolling is part of an activity where it is essential.” All three conditions have to be true before you need the control, which is why a blink that ends inside five seconds passes with no button. W3C’s own examples include an advert that “blinks to get viewers attention but stops after 5 seconds”.
Success Criterion 2.3.1, Three Flashes or Below Threshold, is about seizures: “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.” One off and on cycle is one flash, so the 1 second blink above is one flash per second, and you’d have to shorten the cycle to under a third of a second to cross the line. W3C spells out how the two rules meet: “If blinking occurs faster than 3 per second, it would also be considered a flash.” Unlike 2.2.2, there’s no five-second allowance here and no button that makes it acceptable.
The thresholds in that second clause are about brightness and size. A general flash is a pair of opposing changes in relative luminance of 10% or more where the darker state is below 0.80, and it only counts once the flashing area is more than 25% of any 10 degree visual field, which W3C estimates as a 341 × 256 pixel rectangle on a 1024 × 768 screen. A line of body text sits well under that. A full-width banner in huge type is where you’d start measuring. Saturated red has its own stricter definition, so pure red is the worst colour to pick for something large that flashes.
Respecting reduced motion
The prefers-reduced-motion block in each snippet switches the animation off for people who have turned on the reduce motion setting in their operating system (on a Mac that’s System Settings → Accessibility → Motion → Reduce motion in macOS Tahoe, and under Display in earlier versions). MDN lists the media feature as available in all major browsers since January 2020. With the setting emulated in Chrome, all three snippets on this page showed steady text from the first frame.
Two cautions. The text loses its emphasis for those readers, so if the blink was carrying a message (“this is the deadline”), give the element something static inside the same media query, such as bold or a background colour. And the setting is opt-in, so it doesn’t replace the five-second rule: most people who find blinking hard to read around have never opened that panel.
Blinking text where CSS can’t run
All of the above needs a page you can add a stylesheet to. Plenty of places people want blinking text don’t allow one.
| Where | Does the CSS blink work? |
|---|---|
| Your own web page | Yes |
Mostly no. Can I Email estimates @keyframes support at about 34% of clients, with Gmail and Outlook for Windows among those that don’t support it (their test dates from May 2021) | |
| GitHub README | No. GitHub’s markup pipeline removes inline styles and class attributes |
| Notion, Google Slides | No. Neither gives you anywhere to put CSS |
They all take an image, though, so the route is a GIF with the blink already in it (older Outlook for Windows shows only its first frame). Our text to GIF maker has a look called Flashing that switches the words on and off about every 360 ms, and it exports a GIF or an animated PNG. This is that look, rendered live:
Type your own line, pick the font and colours, and download the file. Then it goes in like any other image: the guides to adding a GIF to an email signature and adding a GIF to a website cover the placement.
A GIF doesn’t get you out of the rules above when it sits on a web page. WCAG treats a looping blink in an image the same as one in CSS, and its technique for images (G152) is to set the GIF to stop after a number of cycles that fits inside five seconds. An image also can’t see prefers-reduced-motion, so on your own site, where you have the choice, the CSS version is the better one. Keep the GIF for the places in the table that leave you no other way.