How to make blinking/flashing text with CSS 3

You are first setting opacity: 1; and then you are ending it on 0, so it starts from 0% and ends on 100%, so instead just set opacity to 0 at 50% and the rest will take care of itself.

Demo

.blink_me {
  animation: blinker 1s linear infinite;
}

@keyframes blinker {
  50% {
    opacity: 0;
  }
}
<div class="blink_me">BLINK ME</div>

Here, I am setting the animation duration to be 1 second, and then I am setting the timing to linear. That means it will be constant throughout. Last, I am using infinite. That means it will go on and on.

Note: If this doesn't work for you, use browser prefixes like -webkit, -moz and so on as required for animation and @keyframes. You can refer to my detailed code here


As commented, this won't work on older versions of Internet Explorer, and for that you need to use jQuery or JavaScript...

(function blink() {
  $('.blink_me').fadeOut(500).fadeIn(500, blink);
})();

Thanks to Alnitak for suggesting a better approach.

Demo (Blinker using jQuery)


The best way to get a pure "100% on, 100% off" blink, like the old <blink> is like this:

.blink {
  animation: blinker 1s step-start infinite;
}

@keyframes blinker {
  50% {
    opacity: 0;
  }
}
<div class="blink">BLINK</div>

Use the alternate value for animation-direction (and you don't need to add any keframes this way).

alternate

The animation should reverse direction each cycle. When playing in reverse, the animation steps are performed backward. In addition, timing functions are also reversed; for example, an ease-in animation is replaced with an ease-out animation when played in reverse. The count to determinate if it is an even or an odd iteration starts at one.

CSS:

.waitingForConnection {
  animation: blinker 1.7s cubic-bezier(.5, 0, 1, 1) infinite alternate;  
}
@keyframes blinker { to { opacity: 0; } }

I've removed the from keyframe. If it's missing, it gets generated from the value you've set for the animated property (opacity in this case) on the element, or if you haven't set it (and you haven't in this case), from the default value (which is 1 for opacity).

And please don't use just the WebKit version. Add the unprefixed one after it as well. If you just want to write less code, use the shorthand.

.waitingForConnection {
  animation: blinker 1.7s cubic-bezier(.5, 0, 1, 1) infinite alternate;  
}
@keyframes blinker { to { opacity: 0; } }

.waitingForConnection2 {
  animation: blinker2 0.6s cubic-bezier(1, 0, 0, 1) infinite alternate;  
}
@keyframes blinker2 { to { opacity: 0; } }

.waitingForConnection3 {
  animation: blinker3 1s ease-in-out infinite alternate;  
}
@keyframes blinker3 { to { opacity: 0; } }
<div class="waitingForConnection">X</div>
<div class="waitingForConnection2">Y</div>
<div class="waitingForConnection3">Z</div>

Alternatively if you do not want a gradual transition between show and hide (e.g. a blinking text cursor) you could use something like:

/* Also use prefixes with @keyframes and animation to support current browsers */
@keyframes blinker {  
  from { visibility: visible }
  to { visibility: hidden }

  /* Alternatively you can do this:  
  0% { visibility: visible; }
  50% { visibility: hidden; }
  100% { visibility: visible; }
  if you don't want to use `alternate` */
}
.cursor {
  animation: blinker steps(1) 500ms infinite alternate;
}

Every 1s .cursor will go from visible to hidden.

If CSS animation is not supported (e.g. in some versions of Safari) you can fallback to this simple JS interval:

(function(){
  var show = 'visible'; // state var toggled by interval
  var time = 500; // milliseconds between each interval

  setInterval(function() {
    // Toggle our visible state on each interval
    show = (show === 'hidden') ? 'visible' : 'hidden';

    // Get the cursor elements
    var cursors = document.getElementsByClassName('cursor');
    // We could do this outside the interval callback,
    // but then it wouldn't be kept in sync with the DOM

    // Loop through the cursor elements and update them to the current state
    for (var i = 0; i < cursors.length; i++) {
      cursors[i].style.visibility = show;
    }
  }, time);
})()

This simple JavaScript is actually very fast and in many cases may even be a better default than the CSS. It's worth noting that it is lots of DOM calls that make JS animations slow (e.g. JQuery's $.animate()).

It also has the second advantage that if you add .cursor elements later, they will still animate at exactly the same time as other .cursors since the state is shared, this is impossible with CSS as far as I am aware.


I don't know why but animating only the visibility property is not working on any browser.

What you can do is animate the opacity property in such a way that the browser doesn't have enough frames to fade in or out the text.

Example:

span {
  opacity: 0;
  animation: blinking 1s linear infinite;
}

@keyframes blinking {
  from,
  49.9% {
    opacity: 0;
  }
  50%,
  to {
    opacity: 1;
  }
}
<span>I'm blinking text</span>