Animated Web Banners With CSS3

Today we’re going to take a look at spicing up our web banners, ads or any content for that matter, with CSS3 animations.


Hey there folks! Today we’re going to take a look at spicing up our web banners, ads or any content for that matter, with CSS3 animations.

Firefox and WebKit browsers are currently the only browsers that support CSS animation, but we’ll take a look at how we can easily make these ads also function in other browsers (which I’ll affectionately refer to as 18th century browsers). However, don’t expect perfect support for all browsers (specifically IE 7 and lower) when experimenting with modern CSS techniques.

Ok then, let’s build some kick-butt, animated web banners!

Please note: In order to save space, all vendor prefixes have been removed. Refer to the source files for the complete CSS. If you are unfamiliar with CSS animations, I’d highly recommend reading this first.

The Markup

First off, we’re going to structure the ad’s elements by laying out the HTML. At this point, we’ll need to think through how we want the animation to function – as this will effect the child/parent structure of our markup (I’ll explain further below):

<div id="ad-1">
	<div id="content">
		<h2>Lost at sea?</h2>
		<h3>Relax - we've got your rudder.</h3>
			<input type="text" id="email" value="Email address..." />
			<input type="submit" id="submit" value="Guide me" />
	<div id="clouds">
		<ul id="cloud-group-1">
			<li class="cloud-1"></li>
			<li class="cloud-2"></li>
			<li class="cloud-3"></li>
		<ul id="cloud-group-2">
			<li class="cloud-1"></li>
			<li class="cloud-2"></li>
			<li class="cloud-3"></li>
	<ul id="boat">
			<div id="question-mark"></div>
	<ul id="water">
		<li id="water-back"></li>
		<li id="water-front"></li>


In order to understand our markup structure, let’s focus in on the boat for a second:

<ul id="boat"> <!-- Groups the boat's elements -->
	<li> <!-- The boat itself -->
		<div id="question-mark"></div> <!-- The question mark (no crap) -->

Now, when you view the first ad on the demo page, there are 3 separate animations taking place on the boat:

  1. An animation that slides the boat in from the left. This is applied directly to the unordered list (group).

  2. An animation that gives the boat a nice bobbing effect – simulating the boat floating on water. This is applied directly to the list element (boat).

  3. An animation that fades in the question mark. This is applied directly to the div (question mark).

If you’re not already seasick, take another look at the demo page. You’ll see that the bobbing animation applied to the list item (the boat) also affects the div inside of it (the question mark). Similarly, the “slide in” animation that is applied to the unordered list (group) also affects the list item and div inside of it (the boat and question mark). This leads us to an important observation:

Child elements take on their parent’s animation in addition to their own animation. With this knowledge added to our arsenal, we’re just a number of child/parent structures away from creating animations that’ll blow minds (and the processor on your Grandma’s laptop)!


Before we jump into the really fun stuff and start animating, we still need to style the ad and come up with a pure CSS fallback for browsers stuck in the 18th century.

The Fallback For 18th Century Browsers

We’ll create a fallback by simply styling the markup as if CSS animations don’t exist (the thought of CSS animations being non-existent is enough to make any grown man cry – but hang in there with me). In other words, if our animations aren’t able to play, the ad should still look decent. This way, when someone is viewing your ad with an 18th century browser, they will see a normal, static web ad – instead of blank ad space.

For example: If someone were to use CSS like this, they’d be in trouble:

/* WRONG WAY! */

@keyframe our-fade-in-animation {
	0%   {opacity:0;}
	100% {opacity:1;}

div {
	opacity: 0; /* This div is hidden by default - a big no-no!*/
	animation: our-fade-in-animation 1s 1;

If a user’s browser doesn’t support animations, the div will remain invisible for the rest of its sad and lonely life. This is when their client breaks down the door of their office – chainsaw in hand – and demands to know why they haven’t sold a single too-too (or whatever their client is selling)! While failing to comprehend how a browser could be so pathetic, their life will end miserably as they curses Internet Explorer with their last breath…

Don’t worry though – neither of us have to be in that poor, developer’s shoes. This is how we’ll provide increased browser support:


@keyframe our-fade-in-animation {
	0%   {opacity:0;}
	100% {opacity:1;}

div {
	opacity: 1; /* This div is visible by default */
	animation: our-fade-in-animation 1s 1;

As you can see, the div will show even if the animation is not able to play. If the animation is able to play like God intended, the div will instantly hide and the epic animation you created will follow through.

The Meat

Now that we know how to make our animated ads play nicely with 18th century browsers (and avoid being hacked to pieces by our clients), let’s get to the meat of the CSS and lay this ad out.

While we are doing this, there are 3 key things to keep in mind:

  1. Since these ads could be used on different websites, we’ll make all of our CSS selections very specific. We’ll do this by starting every selector with the id: #ad-1. This will keep our ad’s styles from interfering with existing styles and elements.

  2. We will purposefully ignore the animation delay feature when setting up our animations. If we used the animation delay feature, as well as styling our elements the correct way (visible by default), things would abruptly fly off the screen (or hide) when their animation finally played. This is why it’s key for our animations to start instantly – allowing our animations enough time to hide and move elements off the screen before they actually display. We will simulate an animation delay by increasing the duration of the animation and manually adjusting keyframes. You’ll see examples of this when we start animating.

  3. Whenever possible, use one animation for multiple elements. This way we can save a lot of time and cut down on code bloat (nobody wants a sumo sitting on their bandwidth). You can create slightly different effects with the same animation by adjusting duration and easing.

Alrighty, we’ll start by setting up our “canvas” for the ad. Let’s make sure it has a relative position so that element’s inside can be positioned correctly. We also need to make sure that any overflow is hidden:

#ad-1 {
	width: 720px;
	height: 300px;
	float: left;
	margin: 40px auto 0;
	background-image: url(../images/ad-1/background.png);
	background-position: center;
	background-repeat: no-repeat;
	overflow: hidden;
	position: relative;
	box-shadow: 0px 0px 6px #000;

Next, we’ll style the text and input fields and call for the corresponding animations. We also want to make sure this content has the highest z-index of all our moving parts – that way it can’t be accidentally covered up:

#ad-1 #content {
	width: 325px;
	float: right;
	margin: 40px;
	text-align: center;
	z-index: 4;
	position: relative;
	overflow: visible;
#ad-1 h2 {
	font-family: 'Alfa Slab One', cursive;
	color: #137dd5;
	font-size: 50px;
	line-height: 50px;
	text-shadow: 0px 0px 4px #fff;
	animation: delayed-fade-animation 7s 1 ease-in-out; /* This will fade in our h2 with a simulated delay */
#ad-1 h3 {
	font-family: 'Boogaloo', cursive;
	color: #202224;
	font-size: 31px;
	line-height: 31px;
	text-shadow: 0px 0px 4px #fff;
	animation: delayed-fade-animation 10s 1 ease-in-out; /* This will fade in our h3 with a simulated delay */
#ad-1 form {
	margin: 30px 0 0 6px;
	position: relative;
	animation: form-animation 12s 1 ease-in-out;  /* This will slide in our email address form with a cool elastic effect. This also has a simulated delay */
#ad-1 #email {
	width: 158px;
	height: 48px;
	float: left;
	padding: 0 20px;
	font-size: 16px;
	font-family: 'Lucida Grande', sans-serif;
	color: #fff;
	text-shadow: 1px 1px 0px #a2917d;
	border-top-left-radius: 5px;
	border-bottom-left-radius: 5px;
	border:1px solid #a2917d;
	outline: none;
	box-shadow: -1px -1px 1px #fff;
	background-color: #c7b29b;
	background-image: linear-gradient(bottom, rgb(216,201,185) 0%, rgb(199,178,155) 100%);
#ad-1 #email:focus {
	background-image: linear-gradient(bottom, rgb(199,178,155) 0%, rgb(199,178,155) 100%);
#ad-1 #submit {
	height: 50px;
	float: left;
	cursor: pointer;
	padding: 0 20px;
	font-size: 20px;
	font-family: 'Boogaloo', cursive;
	color: #137dd5;
	text-shadow: 1px 1px 0px #fff;
	border-top-right-radius: 5px;
	border-bottom-right-radius: 5px;
	border:1px solid #bcc0c4;
	border-left: none;
	background-color: #fff;
	background-image: linear-gradient(bottom, rgb(245,247,249) 0%, rgb(255,255,255) 100%);
#ad-1 #submit:hover {
	background-image: linear-gradient(bottom, rgb(255,255,255) 0%, rgb(255,255,255) 100%);

Now we’re going to style the water and call for the corresponding animations:

#ad-1 ul#water{
	/* If we wanted to add another animation to the water (move it horizontally for instance), we could do that here */
#ad-1 li#water-back {
	width: 1200px;
	height: 84px;
	background-image: url(../images/ad-1/water-back.png);
	background-repeat: repeat-x;
	z-index: 1;
	position: absolute;
	bottom: 10px;
	left: -20px;
	animation: water-back-animation 3s infinite ease-in-out; /* Bobbing water effect */
#ad-1 li#water-front {
	width: 1200px;
	height: 158px;
	background-image: url(../images/ad-1/water-front.png);
	background-repeat: repeat-x;
	z-index: 3;
	position: absolute;
	bottom: -70px;
	animation: water-front-animation 2s infinite ease-in-out; /* Another bobbing water effect - yet slightly different. We'll make this animation move a little bit faster in order to create some perspective. */

Let’s style the boat and all of its elements. Again, we’ll need to make calls for the corresponding animations:

#ad-1 ul#boat {
	width: 249px;
	height: 215px;
	z-index: 2;
	position: absolute;
	bottom: 25px;
	left: 20px;
	overflow: visible;
	animation: boat-in-animation 3s 1 ease-out; /* Slides the group in when ad starts */
#ad-1 ul#boat li {
	width: 249px;
	height: 215px;
	background-image: url(../images/ad-1/boat.png);
	position: absolute;
	bottom: 0px;
	left: 0px;
	overflow: visible;
	animation: boat-animation 2s infinite ease-in-out; /* Simulate the boat bobbing on the water - similar to the animation already used on the water itself. */
#ad-1 #question-mark {
	width: 24px;
	height: 50px;
	background-image: url(../images/ad-1/question-mark.png);
	position: absolute;
	right: 34px;
	top: -30px;
	animation: delayed-fade-animation 4s 1 ease-in-out; /* Fade in the question mark */

Last but not least, we’ll style the cloud groups and the single clouds. We’ll also call a pretty nifty animation that will give them a continuous, scrolling effect. Here’s an illustration of what’s going on:


Now here’s the CSS:

#ad-1 #clouds {
	position: absolute;
	top: 0px;
	z-index: 0;
	animation: cloud-animation 30s infinite linear; /* Scrolls the clouds off to the left, resets, and repeats */
#ad-1 #cloud-group-1 {
	position: absolute;
#ad-1 #cloud-group-2 {
	width: 720px;
	position: absolute;
	left: 720px;
#ad-1 .cloud-1 {
	width: 172px;
	height: 121px;
	background-image: url(../images/ad-1/cloud-1.png);
	position: absolute;
	top: 10px;
	left: 40px;
#ad-1 .cloud-2 {
	width: 121px;
	height: 75px;
	background-image: url(../images/ad-1/cloud-2.png);
	position: absolute;
	top: -25px;
	left: 300px;
#ad-1 .cloud-3 {
	width: 132px;
	height: 105px;
	background-image: url(../images/ad-1/cloud-3.png);
	position: absolute;
	top: -5px;
	left: 530px;

Phew! That was a lot of CSS. Hang in there, the fun part is next!

The Animations

Remember: Up to this point, nothing is actually being animated. If you were to view the ad now, you would see what 18th century browsers will render – a static ad. We will now actually create the animations we have previously called for in our CSS.

Now that our ad is displaying nicely, let’s give this static ad a shock and bring it to life (horrible pun is 100% intended)! Let’s jump right in – I’ll walk you through what’s going on in the comments:

/* An animation with a simulated delay used to fade in multiple elements. We've achieved a simulated delay by starting the fade in process 80% of the way through the animation (instead of starting the process immediately). We can use this technique and increase the animation duration on any element to reach the desired delay duration: */

@keyframes delayed-fade-animation {
	0%   {opacity: 0;}
	80%  {opacity: 0;}
	100% {opacity: 1;}

/* An animation that will slide in our email address form. We've spiced this animation up by overshooting the desired position and sliding it back - this creates a nice elastic effect. As you can see, this animation also uses a simulated delay: */

@keyframes form-animation {
	0%   {opacity: 0; right: -400px;}
	90%  {opacity: 0; right: -400px;}
	95%  {opacity: 0.5; right: 20px;}
	100% {opacity: 1; right: 0px;}

/* This is as basic as an animation gets. Only two keyframes and no simulated delay. This animation slides the boat in from the left when the ad begins: */

@keyframes boat-in-animation {
	0%   {left: -200px;}
	100% {left: 20px;}

/* Here's our really cool cloud animation. The first group of clouds will start off aligned in the center with the second group off to the right of the screen. While the left group of clouds is sliding off the screen to the left, the right group will begin to appear on the right side of the screen. As soon as the left group is completely off the screen, the clouds will reset (very quickly) to their original positions and repeat: */

@keyframes cloud-animation {
	0%       {left: 0px;}
	99.9999%   {left: -720px;}
	100%     {left: 0px;}

/* These last 3 animations are all basically the same - the only difference being the position of each element. They will emulate the bobbing effect of an ocean: */

@keyframes boat-animation {
	0%   {bottom: 0px; left: 0px;}
	25%  {bottom: -2px; left: -2px;}
	70%  {bottom: 2px; left: -4px;}
	100% {bottom: -1px; left: 0px;}
@keyframes water-back-animation {
	0%   {bottom: 10px; left: -20px;}
	25%  {bottom: 8px; left: -22px;}
	70%  {bottom: 12px; left: -24px;}
	100% {bottom: 9px; left: -20px;}
@keyframes water-front-animation {
	0%   {bottom: -70px; left: -30px;}
	25%  {bottom: -68px; left: -32px;}
	70%  {bottom: -72px; left: -34px;}
	100% {bottom: -69px; left: -30px;}

Presto! Our ad has finally come to life. šŸ™‚

In Closing

During the course of this tutorial, we learned the key concepts of creating animated, 18th century browser supporting(ish) web ads:

  1. Child elements take on their parent’s animation in addition to their own animation. We can use this to create more complex animations.
  2. When styling our ads, we should use very specific selectors so that our ads won’t interfere with existing CSS.
  3. Position and style elements so that if our animations aren’t able to run, the ad will still look decent.
  4. When possible, use one animation for multiple elements – save time and code bloat.
  5. Frequently refer to Internet Explorer as “the 18th century browser” while shaking your fist in disgust and anger.

Don’t let your creativity be limited by these examples – there are plenty of other creative things you can do with CSS animations that I didn’t cover. For instance, try playing around with CSS transformations.

Thanks for reading and happy CSS’ing!

Tagged with:

Caleb Jacob

Caleb Jacob is an 18 year old design ninja aspiring to create epic user experiences. He is currently employed as WagePoint's lead designer and developer. He is also addicted to ketchup...

Stay in the loop: Get your dose of frontend twice a week

šŸ‘¾ Hey! Looking for the latest in frontend? Twice a week, we'll deliver the freshest frontend news, website inspo, cool code demos, videos and UI animations right to your inbox.

Zero fluff, all quality, to make your Mondays and Thursdays more creative!

Feedback 45

Comments are closed.
  1. Nice work, should it work in FF9? Because it doesn’t here… my bad maybe? Thank you for your work its awesome! Works great in Chrome!

  2. Amazing stuff. Would be neat to see a tutorial on how to create a similar animated effect with jquery.

  3. @Dejan

    It seems that FireFox 9 might have a CSS animation bug. I’m going to look into it further. Thanks for pointing that out!

  4. @Dejan @Caleb It works fine in my Firefox 9… Dejan, do you maybe have AdBlock installed? I believe it might target elements that have IDs or classes that contain the word “ad” šŸ™‚

  5. @Mary Lou

    Great observation! AdBlock is too smart for it’s own good. šŸ™‚

    It was working fine when tested locally, so I was really at a loss as to what was going on. It all makes sense now.

    Thanks for pointing that out!

  6. Wow, this is a really good. awesome job.

    @Izul , yeah I think Codrops now become more productive.

  7. now that was awesome !!! Codrops is the most productive blog. Great tutorial to get up with CSS3 animations.

  8. @Caleb @Mary Lou Thank you, I have AdBlock and I have disable it for temporary and its working fine now in FF9. Thanks once again both of you for the information!

    Hmm.. by the way šŸ™‚

    I also have AdBlock in Chrome enabled and its working anyway… hmm… šŸ™‚ interesting isn’t it? Well take care! Thank you for your great work!

  9. Cool!! Nice creativity, it looks wonderful. CSS3 is a powerful tool that provides us capability to design applications according to our imagination. I really enjoyed your article and tutorial. Thanks for sharing it.

  10. Very nice!

    Just one question where does the fallback code go? i cant see it in your style.css?


  11. Thanks! Very nice. Now how do you repeat animation? (i mean, there’s some flash banner that have little `reload` icon for those who want startover the animation)

  12. it’s awesome! but only works on Safari, we need wait 2 years to use this kind of banners, but is a very good begin

    • not really you can code a nice jquery fallback with $.animate() ensuring that you have a future proof model, this is a perfectly executed example and with a little effort it can scale to all.

  13. Great tutorial, the images you selected are very nice , and the design is amazing,
    I really like the colors, it could be use as a 404 page also.

  14. Hi,
    thanks for this tutorial, but there is some problem cant see waves or the boat, i’m on Firefox 10

  15. @Mahmoud : I am on FF10 as well and it plays perfect. Maybe a plugin or addon in your browser messing with it???

  16. It actually doesn’t work properly in Chrome 19.0.1036.7 (some images in background are missing) and it doesn’t animate at all in Opera Next 12.1301.

  17. hi jacob.. i like your tutorial, i just love it, and iā€™d like to put in my wordpress site, can you please tell me how to add this animated banner in sidebar (as a widget), post, page, or my wp template
    thanks anyway for your sharing.. šŸ™‚

    anyway, it works on ff13..great!