Create Stunning Effects With CSS Transition Delays

I’m a huge fan of CSS transitions. Sure, they can be abused but on the whole they’re a really great and easy way to add a little life to your web pages. And let’s face it, they’re flat out fun to play with.

I’ve covered transitions a million different ways, but there’s one feature that I hardly ever touch: transition delays. Why would you want to delay your transition? It turns out that the effects that you can achieve become much more complex and impressive when you incorporate this one extra parameter. Let’s jump in and build some cool demos to show off how it works.

What We’re Building

If you’d like to take a sneak peek at what we’ll be building today, check out the three demos below:

The Syntax

Before we jump into building anything, it’s worth it to refresh ourselves on the CSS transition syntax. There are four different parameters associated with transitions in CSS: property, duration, timing function and delay.

You can set the values for each of these properties individually using the syntax below. Keep in mind that you’ll want to run this code through Prefixr to make sure you’ve covered the various browsers.

transition-property: opacity;
transition-duration: 1s;
transition-timing-function: ease;
transition-delay: 2s;

Though this is the most straightforward way to declare a transition, it’s really a horribly bulky way to go about it. When we account for all of the various required prefixes, this chunk of code becomes enormous:

-webkit-transition-property: opacity;
   -moz-transition-property: opacity;
     -o-transition-property: opacity;
    -ms-transition-property: opacity;
        transition-property: opacity;

-webkit-transition-duration: 1s;
   -moz-transition-duration: 1s;
     -o-transition-duration: 1s;
    -ms-transition-duration: 1s;
        transition-duration: 1s;

-webkit-transition-timing-function: ease;
   -moz-transition-timing-function: ease;
     -o-transition-timing-function: ease;
    -ms-transition-timing-function: ease;
        transition-timing-function: ease;

-webkit-transition-delay: 2s;
   -moz-transition-delay: 2s;
     -o-transition-delay: 2s;
    -ms-transition-delay: 2s;
        transition-delay: 2s;

As you can see, this is a heck of a lot of code for one simple transition. For this reason, coders typically utilize the much more concise shorthand version. With this method, we can take the huge chunk of code above and convert it to the following, much more manageable snippet.

-webkit-transition: opacity 1s ease 2s;
   -moz-transition: opacity 1s ease 2s;
     -o-transition: opacity 1s ease 2s;
    -ms-transition: opacity 1s ease 2s;
        transition: opacity 1s ease 2s;

The Shorthand Syntax

To be sure we’re all on the same page, here’s a visual breakdown of the transition shorthand.


As you can see, the traditional method is to list the property that you want to enable the transition on, followed by the duration of the transition, the easing function and finally the delay. This syntax isn’t super strict though. For instance, you can swap the position of the easing function and the delay and the transition will still work. However, the order shown above is from the official spec so I recommend sticking to it.

One thing that I do frequently though is simply leave off the delay property. It defaults to zero seconds, so in the event that you want no delay, you can simply write the following:

transition: opacity 1s ease;

The Power of Transition Delays

Now that we understand the syntax behind transitions, let’s talk about why in the world you would want a delay on a transition. There may be several reasons that you might want to use this property, but the one that I’m going to focus on today is accomplishing complex animations involving multiple steps. We’ve played with multiple step transitions a little bit in previous articles but today we’re really going to have some fun.

Basically, the concept here is that you trigger two or more transitions on an event, but use delays to make them occur at different times. So let’s say we have our first transition set to last for one second, we can then set a delay of one second on our second transition to make it begin as soon as the first one ends. The results can be quite impressive!

Sequential Message

The first idea that pops into my head for utilizing delays is to set up some sort of message that presents itself to the user one piece at a time. Let’s say we want to have three pieces of text that fly in and out of a div at different times. The first step is to lay out how it all works so you can wrap your mind around it.

  • Default Message: “Hover Here”
  • One second fly out of “Hover Here”
  • Wait one second, then fly in second message: “Greetings!”
  • Wait two seconds, then fly in third message: “How are you?”
  • Hover out returns to default message

As you can see, we’ll first instruct the user to hover over the div, then fly out the hover message as two more messages fly in, the first of which will wait one second and the second will wait two seconds.


To bring this demo to life, we need a div that contains three different paragraphs like so. Obviously, if you were using this is a live project, you’d want to apply a class or ID, but I’ll keep it simple here.

  <p>Hover Here</p>
  <p><small>How Are You?</small></p>


To start the CSS, we’ll style the div and paragraphs. There are a few important things here to consider. First, notice the relative positioning and the hidden overflow on the div, these are important so be sure to include them.

Next, notice that I’ve absolutely positioned the text items and pushed them up and out of the bounds of the div so that they’re not visible by default. I also included a completely optional fancy Sass 3D effect. For the complete mixin, check out this article.

div {
  height: 300px;
  background: #f3f3f3;
  position: relative;
  overflow: hidden;

p {
  position: absolute;
  left: 10%;
  margin: 0;
  top: -200px;
  font: bold 70px/1 Helvetica, sans-serif;
  color: #6d879d;
  @include threedeetext(#6d879d);

small {
  font-size: 40px;

Now it’s time to nudge our first paragraph into place and create our first transition. To do this, we’ll use the nth-child selector to target the first paragraph (“Hover Here”). Place it fifty pixels from the top, add a one second transition with no delay and create a hover effect that zooms it out of view.

/*Hover Here Text*/
  top: 50px;
  -webkit-transition: top 1s ease;
     -moz-transition: top 1s ease;
       -o-transition: top 1s ease;
      -ms-transition: top 1s ease;
          transition: top 1s ease;

div:hover p:nth-child(1) {
  top: -100px;

To finish off this demo, we need to create a hover event for the second and third paragraphs. They’re basically the same, just make sure that the “Greetings” paragraph has a one second delay and the “How are you?” paragraph has a two second delay. Also be sure to position the last paragraph further down.

/*Greetings Hover*/
div:hover p:nth-child(2) {
  top: 50px;
  -webkit-transition: top 1s ease 1s;
     -moz-transition: top 1s ease 1s;
       -o-transition: top 1s ease 1s;
      -ms-transition: top 1s ease 1s;
          transition: top 1s ease 1s;

/*How Are You? Hover*/
div:hover p:nth-child(3) {
  top: 110px;
  -webkit-transition: top 1s ease 2s;
     -moz-transition: top 1s ease 2s;
       -o-transition: top 1s ease 2s;
      -ms-transition: top 1s ease 2s;
          transition: top 1s ease 2s;

/*Hover Out Transitions*/
p:nth-child(3), p:nth-child(2) {
  -webkit-transition: top 0.2s ease 0s;
     -moz-transition: top 0.2s ease 0s;
       -o-transition: top 0.2s ease 0s;
      -ms-transition: top 0.2s ease 0s;
          transition: top 0.2s ease 0s;

Live Demo

That’s all there is to it! Now let’s check out the live demo on Tinkerbin. Here you’ll be able to see and tweak the code, be sure to play around and see what you can come up with!

Demo: Click here to launch. Note that you’ll have to change the CSS mode to “Sass” and hit “Run” to see the 3D text effect.


One Letter At a Time

For this one, we’re only going to use a single message. However, each letter of the message will come flying into place individually. The result will be really cool and very different from what you traditionally see done with CSS.


Unfortunately, CSS doesn’t have a great way to target individual letters in a string (yet), so our HTML has to get all messy with spans. It’s a pain and the code looks a little sloppy, but it’s the best we can do without bringing JavaScript into the picture, which is out of the scope of this tutorial.



Our first chunk of CSS will set up our div, just like last time, and style the letters. I’m using the Google Web font “Bree Serif”. I also set the opacity to 0, the position to absolute and transformed the text to uppercase.

div {
  background: #eee;
  height: 200px;
  position: relative;

span {
  font: 400 100px/1 'Bree Serif', Helvetica, sans-serif;
  margin: 50px;
  opacity: 0;
  text-transform: uppercase;
  position: absolute;

Now we have to apply a different transition to each individual letter. To accomplish this, use nth-child just like last time and target the spans. Notice how the primary difference here is that the delay reduces each time, starting at 0.4s and making its way down to 0.

span:nth-child(5) {
  -webkit-transition: all 0.1s ease 0.4s;
     -moz-transition: all 0.1s ease 0.4s;
       -o-transition: all 0.1s ease 0.4s;
      -ms-transition: all 0.1s ease 0.4s;
          transition: all 0.1s ease 0.4s;

span:nth-child(4) {
  -webkit-transition: all 0.1s ease 0.3s;
     -moz-transition: all 0.1s ease 0.3s;
       -o-transition: all 0.1s ease 0.3s;
      -ms-transition: all 0.1s ease 0.3s;
          transition: all 0.1s ease 0.3s;

span:nth-child(3) {
  -webkit-transition: all 0.1s ease 0.2s;
     -moz-transition: all 0.1s ease 0.2s;
       -o-transition: all 0.1s ease 0.2s;
      -ms-transition: all 0.1s ease 0.2s;
          transition: all 0.1s ease 0.2s;

span:nth-child(2) {
  -webkit-transition: all 0.1s ease 0.1s;
     -moz-transition: all 0.1s ease 0.1s;
       -o-transition: all 0.1s ease 0.1s;
      -ms-transition: all 0.1s ease 0.1s;
          transition: all 0.1s ease 0.1s;

span:nth-child(1) {
  -webkit-transition: all 0.1s ease;
     -moz-transition: all 0.1s ease;
       -o-transition: all 0.1s ease;
      -ms-transition: all 0.1s ease;
          transition: all 0.1s ease;

To finish this one off, we first need to declare what happens when we hover over the div. I set the spans to have an opacity of 1, brought them in from the left, and rotated them 360 degrees so that they spin into place.

From here, all that’s left is to push each individual letter into place on hover. With that finished, a single hover event will cause all of the letters to become visible and spin into place and our delays will ensure that all of this takes place sequentially.

div:hover span {
  opacity: 1;
  left: 50px;
  -webkit-transform: rotate(360deg);
     -moz-transform: rotate(360deg);
       -o-transform: rotate(360deg);
      -ms-transform: rotate(360deg);
          transform: rotate(360deg);

div:hover span:nth-child(2) {
  left: 120px;

div:hover span:nth-child(3) {
  left: 175px;

div:hover span:nth-child(4) {
  left: 230px;

div:hover span:nth-child(5) {
  left: 280px;

Live Demo

With that, we’re all finished. Be sure to stop by the demo below and hover over the div to see the animation and tweak it for your own uses.

Demo: Click here to launch.


Curtain Effect

By now you get the gist of how it all works, so I won’t bore you with more explanation, but I did come up with one more demo that I thought was fun. This one uses a stack of images that gradually fall away to reveal the final image on the bottom of the stack. It’s a staggered curtain effect that is definitely a lot more than you’d expect to get on a single CSS hover event.

Demo: Click here to launch.

How Do You Use Transition Delays?

Now that you’ve see some of the ideas that I’ve had for creatively using transition delays, I’d love to see what you’ve come up with. Leave a link below and show me what you’ve got!