Select Page


Another of my pens on codepen.io was picked to feature on the front page recently, so I thought I’d take the most complicated part of it out and walk you through the concept and steps to loop CSS animation and the tricks that worked for me.


Back to Basics

There’s no easy way to loop css animation if the element doesn’t return back to it’s original position or never fully leaves the frame, so for objects only moving in one direction (like falling snow), we need find another way around it.

For example, the movement in the first two animations loop easily- the object returns to it’s original position in the first, and it completely exits the frame in the second. I’ve included that little timeline graphic to help visualise where the animation begins and ends.

CSS:

.obj01 {
  animation: anim-ex-01 linear 2s;
  animation-iteration-count: infinite;
  width:50px;
  height:50px;
  background:#eb5252;
  border-radius:50%;
}

@keyframes anim-ex-01{
  0% {transform: translate(0px,0px);}
  50% {transform: translate(50px,50px);}
  100% {transform: translate(0px,0px);}
}

Result:

0%

100%

 


CSS:

.obj02 {
  animation: anim-ex-02 linear 2s;
  animation-iteration-count: infinite;
  width:50px;
  height:50px;
  background:#eb5252;
  border-radius:50%;
}

@keyframes anim-ex-02{
  0% {transform: translate(47px,-100px);}
  100% {transform: translate(47px,200px);}
}

Result:

0%

100%

 


Simple Looping Road Example

So what if we want to make an animation that never leaves the screen and only moves in one direction? For example, lets create a looping animation of a simple road.

CSS:

.road {
  width:130px;
  height:150px;
  background:darkgrey;
  border-width: 0 10px 0 10px;
  border-style:solid;
  border-color:green;
  overflow:hidden;
}

.road-lines {
  width:10px;
  height:30px;
  background:white;
  margin:auto;
  box-shadow: 0 50px white, 0 100px white;
  animation: anim-ex-road-01 linear 2s;
  animation-iteration-count: infinite;
}

@keyframes anim-ex-road {
  0% {transform: translate(0px,0px);}
  100% {transform: translate(0px,150px);}
}

Result:

0%

100%

 

As you can see, the road just disappears off the bottom of the frame to suddenly pop back on once the animation loops back to the beginning.

To fix this, we need to duplicate our frame and make an exact copy that sits right above the first. This means that when the road lines animate one ‘copy’ down, the duplicate above will rest in the exact position needed to seamlessly loop back to the first frame. The only difference in the following example is the extra box-shadows I’ve added to create the duplicate above the original.

CSS:

.road {
  width:130px;
  height:150px;
  background:darkgrey;
  border-width: 0 10px 0 10px;
  border-style:solid;
  border-color:green;
  overflow:hidden;
}

.road-lines {
  width:10px;
  height:30px;
  background:white;
  margin:auto;
  box-shadow: 0 50px white, 0 100px white, 0 -50px white, 0 -100px white, 0 -150px white;
  animation: anim-ex-road-01 linear 2s;
  animation-iteration-count: infinite;
}

@keyframes anim-ex-road {
  0% {transform: translate(0px,0px);}
  100% {transform: translate(0px,150px);}
}

Result:

0%

100%

 

Here’s the same example, but without overflow:hidden, so you can see whats going on under the hood.

0%

100%

 


Looping Snow Animation

Now we’ve got the basics down, let’s apply what we know to some snowflakes. For my CSS snowglobe above, and for this example, we’re going to use an asterisk * for a snowflake on which we can use text-shadow to duplicate it randomly around the frame. Then, simply copy and paste your text-shadow values and minus the height of your frame (in this case, 150px) from each Y-value to ‘duplicate’ the snowflakes above as we did with the road.

HTML:

<div class="frame">
  <div class="snowflakes">*</div>
</div>

CSS:

.frame {
  width:150px;
  height:150px;
  background:skyblue;
  overflow:hidden;
  position:relative;
}

.snowflakes {
  color:snow;
  font-family: Verdana;
  font-size: 11pt;
  animation: anim-ex-snow linear 4s;
  animation-iteration-count: infinite;
  text-shadow:83px 95px, 112px 82px, 96px 78px, 22px 70px, 64px 68px, 142px 32px, 10px 121px, 149px 110px, 110px 97px, 54px 123px, 61px 89px, 40px 90px, 150px 150px, 132px 30px, 71px 25px, 24px 27px, 87px 90px, 65px 132px, 90px 66px, 138px 99px, 103px 101px, 46px 54px, 56px 82px, 70px 117px, 150px 145px, 142px 126px, 17px 121px, 30px 18px, 29px 137px, 118px 47px, 17px 4px, 133px 42px, 13px 32px,
              /*_________Y-Values -150px_________*/
              83px -55px, 112px -68px, 96px -72px, 22px -80px, 64px -82px, 142px -118px, 10px -29px, 149px -40px, 110px -53px, 54px -27px, 61px -61px, 40px -60px, 150px 0px, 132px -120px, 71px -125px, 24px -123px, 87px -60px, 65px -18px, 90px -84px, 138px -51px, 103px -49px, 46px -96px, 56px -68px, 70px -33px, 150px -5px, 142px -24px, 17px -29px, 30px -132px, 29px -13px, 118px -103px, 17px -146px, 133px -108px, 13px -118px,
              /*_________One extra to duplicate the original asterisk__________*/
              0px -150px;
}

@keyframes anim-ex-snow{
  0% {transform: translate(0px,0px);}
  100% {transform: translate(0px,150px);}
}

Result:

*

To add a parallax effect to the snow we just need to create another layer of random snowflakes, set them to a lower opacity and slow down the animation a little.

HTML:

<div class="frame">
  <div class="snowflakes">*</div>
  <div class="snowflakes rear-layer">*</div>
</div>

CSS:

.rear-layer {
  position:absolute;
  top:0px;
  opacity:0.5; /*lower opacity to make them appear further away*/
  animation: anim-ex-snow linear 5s; /*add a second or so on to slow the snowflakes down*/
  animation-iteration-count: infinite;
/*create a new set of random coordinates so they look different from the front layer*/
  text-shadow:88px 7px, 67px 44px, 93px 15px, 30px 74px, 12px 34px, 22px 37px, 129px 13px, 66px 41px, 44px 31px, 87px 12px, 87px 99px, 134px 44px, 119px 23px, 108px 71px, 28px 103px, 47px 70px, 123px 78px, 105px 37px, 33px 117px, 113px 118px, 6px 78px, 72px 71px, 110px 128px, 6px 114px, 122px 62px, 51px 111px, 113px 23px, 59px 116px, 130px 35px, 19px 54px, 98px 141px, 133px 23px, 79px 54px, 105px 86px, 32px 50px, 64px 29px,
              /*_________Y-Values -150px_________*/
              88px -143px, 67px -106px, 93px -135px, 30px -76px, 12px -116px, 22px -113px, 129px -137px, 66px -109px, 44px -119px, 87px -138px, 87px -51px, 134px -106px, 119px -127px, 108px -79px, 28px -47px, 47px -80px, 123px -72px, 105px -113px, 33px -33px, 113px -32px, 6px -72px, 72px -79px, 110px -22px, 6px -36px, 122px -88px, 51px -39px, 113px -127px, 59px -34px, 130px -115px, 19px -96px, 98px -9px, 133px -127px, 79px -96px, 105px -64px, 32px -100px, 64px -121px,
              /*_________One extra to duplicate the original asterisk__________*/
              0px -150px;
}

Result:

*
*

 


The Possibilities are Endless

Looping elements in this way opens up so many doors with CSS animation. Check another featured pen of mine, where I used this same technique over and over again to create this parallax effect.

As usual, if you have any comments or queries, please feel free to leave me a message below!