From our sponsor: Meco is a distraction-free space for reading and discovering newsletters, separate from the inbox.
CSS3 opens up so many crazy possibilities and today we want to show you how to go wild with splash and coming soon page effects using CSS3 animations. We’ll experiment with animation sequences and how to bring some life to some simple elements.
The cute shoe photos that we are using in the first demo are by lovely Amira Almajid and you can find the set here.
Please note that the animations will only work in modern browsers that support them.
In order not to bloat the tutorial, I’ve omitted the CSS vendor prefixes but you’ll find them in the downloadable files.
So, let’s go nuts!
Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.
Example 1
Please note, that I added a longer delay for this example to give some time to load the images.
The first example will have a couple of elements that we’ll animate. The theme for this example will be a coming soon page.
We’ll have a main container with a content area. Inside, we’ll place some rows for the thumbnails. Also, we’ll have a content row for the main headlines. After we show the main content area, we’ll slide in the side element which will contain an email imput:
The Markup
<div class="sp-container"> <div class="sp-content"> <div class="sp-row"> <span><img src="images/example1/1.png" /></span> <span><img src="images/example1/2.png" /></span> <span><img src="images/example1/3.png" /></span> <span><img src="images/example1/4.png" /></span> <span><img src="images/example1/5.png" /></span> </div> <div class="sp-row sp-side-row"> <span><img src="images/example1/11.png" /></span> <span><img src="images/example1/12.png" /></span> </div> <div class="sp-row sp-content-row"> <h1>Coming Soon</h1> <h2>Designer Shoes that you dream of for incredible prices</h2> <h1 class="sp-title"><em>Little</em> Blue Shoe</h1> </div> <div class="sp-row sp-side-row"> <span><img src="images/example1/13.png" /></span> <span><img src="images/example1/14.png" /></span> </div> <div class="sp-row"> <span><img src="images/example1/6.png" /></span> <span><img src="images/example1/7.png" /></span> <span><img src="images/example1/8.png" /></span> <span><img src="images/example1/9.png" /></span> <span><img src="images/example1/10.png" /></span> </div> <div class="sp-arrow"></div> </div> <div class="sp-side"> <h2>Be the first to know:</h2> <div class="sp-input"> <input type="text" value="Your email"/> <a href="index.html">Go</a> </div> </div> </div>
Ok, now the exciting part: the CSS!
The CSS
So the main idea of this example is the following sequence of animations:
- Thumbnails appear with fromBack.
- First h1 appears with fromBack.
- Sub headline h2 appears with fromBack.
- First h1 and sub headline h2 disappear with fadeOut.
- Thumbnails start disappearing sequentially with fadeOut and second h1 appears with fadeInColor. Also, the content moves to the left and scales down with sizeDownMove.
- Arrow and side content slide from the left with slideIn
Let’s center the main container and position the content absolutely:
.sp-container { position: relative; width: 1000px; height: 600px; margin: -40px auto 0 auto; } .sp-content { position: absolute; z-index: 100; width: 800px; height: 600px; left: 0px; top: 0px; animation: sizeDownMove 0.9s ease-in-out 6s backwards; transform: scale(0.6); transform-origin: 0% 50%; }
As you can see, we are applying an animation to the content which will move and scale it, but only after 6 seconds. We’ll have a look at those animations later.
The arrow will also be an absolutely positioned element with a background image:
.sp-arrow { background: transparent url(../images/arrow.png) no-repeat top left; position: absolute; top: 50%; margin-top: -77px; left: 82%; width: 198px; height: 155px; animation: slideIn 0.6s ease-in-out 6s backwards; z-index: 100; }
The side element will contain the email input and we’ll place it on the right side of the screen:
.sp-side { width: 460px; height: 300px; position: absolute; right: 10px; top: 25%; animation: slideIn 0.6s ease-in-out 6s backwards; }
The arrow and the side element will both slide in, but we’ll look at that in a minute.
Let’s style the headline:
.sp-side h2 { font-size: 70px; padding: 20px 0px; text-align: center; color: #fff; text-transform: uppercase; text-shadow: 1px 1px 2px rgba(0,0,0,0.2); font-family: 'Unlock', Arial, sans-serif; }
…and the input wrapper with the text input and the button:
.sp-input { background-color: rgba(255,255,255,0.3); height: 30px; padding: 20px; border-radius: 10px; margin: 0 auto; width: 260px; } .sp-input input[type="text"] { width: 210px; padding: 6px; background-color: #fff; border: 1px solid #ddd; border-radius: 4px; float: left; font-family: 'Cookie', serif; font-size: 18px; } .sp-input input[type="text"]:focus { outline-color: #acdacf; } .sp-input a { float: left; background-color: #418e7b; color: #fff; width: 30px; height: 30px; border: none; border-radius: 50%; margin-left: 5px; text-align: center; line-height: 30px; cursor: pointer; font-family: 'Unlock', Arial, sans-serif; } .sp-input a:hover { background-color: #fff; color: #418e7b; }
Now, let’s look at the stuff inside of the main content. First, we’ll style the headline which will be animated to appear coming from the back and then later we’ll fade it out:
.sp-content h1:first-child { font-size: 100px; text-align: center; color: #fff; text-transform: uppercase; text-shadow: 1px 1px 2px rgba(0,0,0,0.2); line-height: 80px; padding: 30px 0px 20px 0px; font-family: 'Unlock', Arial, sans-serif; animation: fromBack 1.2s ease-in-out 1.5s backwards, fadeOut 0.5s linear 4.5s forwards; }
The second headline will only fade in later, after the first one’s gone:
.sp-content h1.sp-title { font-size: 90px; line-height: 80px; position: absolute; top: 50px; left: 160px; width: 470px; border-radius: 50%; background-color: rgba(255, 255, 255, 0.3); padding-top: 155px; height: 305px; text-transform: uppercase; text-align: center; color: #518f7e; text-shadow: 1px 1px 1px rgba(255,255,255,0.9); font-family: 'Unlock', Arial, sans-serif; animation: fadeInColor 1.2s linear 5.2s backwards; } .sp-content h1:last-child em { font-family: 'Cookie', serif; text-transform: none; }
The sub headline will, just like the first H1, appear and then fade out:
.sp-content h2 { font-size: 36px; text-align: center; color: #518f7e; font-family: 'Cookie', serif; text-shadow: 1px 1px 1px rgba(255,255,255,0.9); opacity: 0; animation: fromBack 0.6s ease-in-out 2.6s backwards, fadeOut 0.5s linear 4.5s backwards; }
Now, let’s style those rows to place the thumbs:
.sp-content-row { width: 466px; height: 300px; float: left; } .sp-side-row { width: 150px; float: left; } .sp-row img { display: block; z-index: 1000; position: relative; }
Each of the thumb spans are as well appear by scaling them from 0 to 1 which will make it look as if they come in from the back. Then later, we want to fade them out:
.sp-row span { position: relative; float: left; margin: 2px; z-index: 100; transform: scale(1); opacity: 0; animation: fromBack 0.4s linear backwards, fadeOut 0.3s linear backwards; }
We want to create a sequence where each following thumb appears and disappears with a delay. So, we will take each row and specify those delays for each span child element. Notice that the 4th row is the one on the right side, so we make it appear as if we go clockwise:
.sp-row:nth-child(1) span:nth-child(1) { animation-delay: 0s, 5s; } .sp-row:nth-child(1) span:nth-child(2) { animation-delay: 0.1s, 5.1s; } .sp-row:nth-child(1) span:nth-child(3) { animation-delay: 0.2s, 5.2s; } .sp-row:nth-child(1) span:nth-child(4) { animation-delay: 0.3s, 5.3s; } .sp-row:nth-child(1) span:nth-child(5) { animation-delay: 0.4s, 5.4s; } .sp-row:nth-child(4) span:nth-child(1) { animation-delay: 0.5s, 5.5s; } .sp-row:nth-child(4) span:nth-child(2) { animation-delay: 0.6s, 5.6s; } .sp-row:nth-child(5) span:nth-child(5) { animation-delay: 0.7s, 5.7s; } .sp-row:nth-child(5) span:nth-child(4) { animation-delay: 0.8s, 5.8s; } .sp-row:nth-child(5) span:nth-child(3) { animation-delay: 0.9s, 5.9s; } .sp-row:nth-child(5) span:nth-child(2) { animation-delay: 1s, 6s; } .sp-row:nth-child(5) span:nth-child(1) { animation-delay: 1.1s, 6.1s; } .sp-row:nth-child(2) span:nth-child(2) { animation-delay: 1.2s, 6.2s; } .sp-row:nth-child(2) span:nth-child(1) { animation-delay: 1.3s, 6.3s; }
Let’s create a little pseudo element to decorate the thumbs with a circle in the backround:
.sp-row span:before { content: ''; position: absolute; background-color: rgba(255,255,255,0.3); width: 100px; height: 100px; top: 50%; left: 50%; margin: -50px 0 0 -50px; border-radius: 50%; }
Now, let’s take a look at the animations.
The first animation simply fades out an element by setting the opacity from 1 to 0:
@keyframes fadeOut{ 0%{ opacity: 1; } 100%{ opacity: 0; } }
fadeInColor will fade in the element and set a rgba background color. But the opacity level of the rgba will only pass 0 when the opacity of the element itself reaches 0.5. This basically shows the content of the element first and then “fades in” the background. We want the for the second headline:
@keyframes fadeInColor{ 0%{ opacity: 0; background-color: rgba(255,255,255,0); } 50%{ opacity: 0.5; background-color: rgba(255,255,255,0); } 100%{ opacity: 1; background-color: rgba(255,255,255,0.3); } }
The next animation simply makes an element slide in and appear from the left side:
@keyframes slideIn{ 0%{ opacity: 0; transform: translateX(-200px); } 100%{ opacity: 1; transform: translateX(0px); } }
sizeDownMove will scale down the element and move it from left 100px to left 0px. We could also use translate here but since our element is absolute, we can just play with the left:
@keyframes sizeDownMove{ 0%{ transform: scale(1); left: 100px; } 100%{ transform: scale(0.6); left: 0px; } }
The next animation will make an element appear to be coming from the back by scaling it from 0 to 1 and also setting the opacity from 0 to 1:
@keyframes fromBack{ 0%{ transform: scale(0); opacity: 0; } 100%{ transform: scale(1); opacity: 1; } }
And that’s all the animations for example 1! Let’s take a look at the next example which will be a bit simpler, I promise!
Example 2
How about a splash page where we show some thoughtful titles in a sequence? In this example, we’ll simply show some sentences one after the other with a nice blurry fade in effect.
The Markup
We’ll again have a container and a content div with some frames inside, each one for a different sentence. Additionally, we’ll have a globe and a link element that will only appear in the end:
<div class="sp-container"> <div class="sp-content"> <div class="sp-globe"></div> <h2 class="frame-1">It's destroying the planet</h2> <h2 class="frame-2">It's mass, mechanized murder</h2> <h2 class="frame-3">You can stop it</h2> <h2 class="frame-4">Now!</h2> <h2 class="frame-5"> <span>Save the planet.</span> <span>Love life.</span> <span>Go vegan.</span> </h2> <a class="sp-circle-link" href="index2.html">Join us!</a> </div> </div>
Let’s look at the style.
The CSS
Each headline is going to be centered on the screen and we’ll make each one appear and disappear using the animation blurFadeInOut:
.sp-container h2 { position: absolute; top: 50%; line-height: 100px; height: 100px; margin-top: -50px; font-size: 100px; width: 100%; text-align: center; color: transparent; animation: blurFadeInOut 3s ease-in backwards; }
Let’s define the delays for each heading:
.sp-container h2.frame-1 { animation-delay: 0s; } .sp-container h2.frame-2 { animation-delay: 3s; } .sp-container h2.frame-3 { animation-delay: 6s; } .sp-container h2.frame-4 { font-size: 200px; animation-delay: 9s; }
The last one will not have an animation itself but instead we’ll animate its spans sequentially:
.sp-container h2.frame-5 { animation: none; color: transparent; text-shadow: 0px 0px 1px #fff; } .sp-container h2.frame-5 span { animation: blurFadeIn 3s ease-in 12s backwards; color: transparent; text-shadow: 0px 0px 1px #fff; } .sp-container h2.frame-5 span:nth-child(2) { animation-delay: 13s; } .sp-container h2.frame-5 span:nth-child(3) { animation-delay: 14s; }
The globe is an absolutely positioned element with a background image. We’ll fade it in after 14 seconds which is after all the previous animations finished. It will be scaled to occupy all the content area:
.sp-globe { position: absolute; width: 282px; height: 273px; left: 50%; top: 50%; margin: -137px 0 0 -141px; background: transparent url(../images/globe.png) no-repeat top left; animation: fadeInBack 3.6s linear 14s backwards; opacity: 0.3; transform: scale(5); }
The “join us” link will be a cicular element that we’ll make appear with a rotation:
.sp-circle-link { position: absolute; left: 50%; bottom: 100px; margin-left: -50px; text-align: center; line-height: 100px; width: 100px; height: 100px; background: #fff; color: #3f1616; font-size: 25px; border-radius: 50%; animation: fadeInRotate 1s linear 16s backwards; transform: scale(1) rotate(0deg); } .sp-circle-link:hover { background: #85373b; color: #fff; }
And now, let’s take a look at all the animations:
The first animation is for all the headlines that are going to appear and then disappear. We’ll simulate a blur effect by playing with the text-shadow and the scale:
@keyframes blurFadeInOut{ 0%{ opacity: 0; text-shadow: 0px 0px 40px #fff; transform: scale(1.3); } 20%,75%{ opacity: 1; text-shadow: 0px 0px 1px #fff; transform: scale(1); } 100%{ opacity: 0; text-shadow: 0px 0px 50px #fff; transform: scale(0); } }
The next animation is almost the same, just that we don’t want the text to disappear (this one is for the last headline that stays):
@keyframes blurFadeIn{ 0%{ opacity: 0; text-shadow: 0px 0px 40px #fff; transform: scale(1.3); } 50%{ opacity: 0.5; text-shadow: 0px 0px 10px #fff; transform: scale(1.1); } 100%{ opacity: 1; text-shadow: 0px 0px 1px #fff; transform: scale(1); } }
The globe will have the following animation that scales the element up and first increases and then decreases its opacity:
@keyframes fadeInBack{ 0%{ opacity: 0; transform: scale(0); } 50%{ opacity: 0.4; transform: scale(2); } 100%{ opacity: 0.2; transform: scale(5); } }
The next animation is for the link element. It will fade in while it’s rotating:
@keyframes fadeInRotate{ 0%{ opacity: 0; transform: scale(0) rotate(360deg); } 100%{ opacity: 1; transform: scale(1) rotate(0deg); } }
Example 3
In the third example we’ll be experimenting with moving around some text to introduce some product or app. In the end of all the animations we’ll make a call-to-action element appear.
The Markup
We’ll have again the same two containers and also two main wrappers for each side. The aim is to divide the area and play with the texts of the two sides:
<div class="sp-container"> <div class="sp-content"> <div class="sp-wrap sp-left"> <h2> <span class="sp-top">What if you wouldn't get</span> <span class="sp-mid">spam</span> <span class="sp-bottom">anymore?</span> </h2> </div> <div class="sp-wrap sp-right"> <h2> <span class="sp-top">Wouldn't that be absolutely</span> <span class="sp-mid">great<i>!</i><i>?</i></span> <span class="sp-bottom">Yeah, it would!</span> </h2> </div> </div> <div class="sp-full"> <h2>A great way to get rid of spam!</h2> <a href="index3.html">Sign up now!</a> </div> </div>
Let’s look at the style.
The CSS
Initially we want to animate the content area which has a pseudo element representing a line in the middle. We’ll “open” it and make the line increase like that.
Then we want show the text on the left side by sliding it in from the right, sequentially. The same happens then on the right, just that we slide from the left. The spans with the class “sp-mid” will have a larger font size, and these are the elements that we want to still show after fading out the rest of the text. We’ll move the two larger texts up and squeeze the content area, i.e. decreasing its height which makes the middle line decrease. After that, we’ll make the resting elements with the sign up button appear.
The container will have a fixed width and height and the content wrapper first appear with the animation open and then decrease its height by applying squeeze. The latter will only happen after all the other text has faded out, hence the long animation delay:
.sp-container { width: 900px; height: 400px; position: relative; margin: 80px auto 0px auto; } .sp-content { width: 100%; height: 400px; position: relative; animation: open 0.4s linear forwards, squeeze 0.6s linear 5.5s forwards; }
The line in the middle is created by a pseudo element:
.sp-content:after { content: ''; width: 4px; background: #000; height: 100%; position: absolute; left: 50%; }
The wrappers for the headlines will not show any overflow, that’s how we ensure that we don’t see any overlapping when sliding them:
.sp-wrap { width: 400px; padding: 0px 25px; height: 100%; text-align: right; font-size: 70px; line-height: 80px; float: left; position: relative; background: #ffdd00; overflow: hidden; }
The h2 elements with the spans inside have the following style:
.sp-container h2 { color: #000; text-shadow: 0px 0px 1px rgba(0,0,0,0.9); } .sp-wrap span { display: block; background: #ffdd00; opacity: 0; } .sp-wrap span.sp-mid { opacity: 1; } .sp-container .sp-right h2 { color: #fff; text-shadow: 0px 0px 1px rgba(255,255,255,0.9); } .sp-wrap span.sp-mid { font-family: 'MisoBold'; text-transform: uppercase; font-size: 160px; line-height: 130px; position: relative; }
The “sp-top” and the “sp-bottom” will slide from the right and then disappear, and the “sp-mid” will move up instead of just fade out:
.sp-left span.sp-top { animation: slideLeft 0.5s ease-in 0.6s backwards, fadeOut 1s linear 4s backwards; } .sp-left span.sp-mid { animation: slideLeft 0.5s ease-in 1s backwards, moveUp 0.6s linear 5s forwards; } .sp-left span.sp-bottom { animation: slideLeft 0.5s ease-in 1.4s backwards, fadeOut 1s linear 4.2s backwards; }
On the right side the same thing is happening, just that we slide the elements from the left:
.sp-right span { text-align: left; } .sp-right span.sp-top { animation: slideRight 0.5s ease-in 2s backwards, fadeOut 1s linear 4.4s backwards; } .sp-right span.sp-mid { animation: slideRight 0.5s ease-in 2.4s backwards, moveUp 0.6s linear 5s forwards; } .sp-right span.sp-bottom { animation: slideRight 0.5s ease-in 3.2s backwards, fadeOut 1s linear 4.6s backwards; }
The question mark will be on top of the exclamation mark, and when we moved the two mid spans up, we will fade out the question mark to reveal the exclamation mark:
.sp-wrap i { position: absolute; background: #ffdd00; width: 60px; } .sp-wrap i:first-child { color: #000; } .sp-wrap i:last-child { opacity: 0; animation: fadeOut 1s linear 6s backwards; }
The text appearing in the end is wrapped by sp-full and we’ll make it fade in and “zoom in” the sign up link:
.sp-full { position: absolute; font-size: 67px; top: 142px; width: 700px; left: 145px; animation: fadeIn 1s linear 6.6s backwards; } .sp-full a { background: #000; color: #fff; border-radius: 4px; padding: 10px 40px; display: inline-block; font-size: 40px; margin-top: 40px; animation: zoomIn 0.7s ease-in-out 7s backwards; } .sp-full h2 { width: 400px; padding: 0px 50px 0px 0px; float: left; text-align: right; } .sp-full a:hover { opacity: 0.8; }
Now, let’s have a look at the animations.
The first animation is for “opening” the content area. This we will achieve by simply scaling its height:
@keyframes open{ 0%{ transform: scale(1,0); } 100%{ transform: scale(1,1); } }
The squeeze animation is not really squeezing anything because we are not using the scaling property here. We don’t want to because we still have some text inside the content area when we are applying it. So, we will simply decrease its height:
@keyframes squeeze{ 0%{ height: 400px; } 100%{ height: 120px; } }
The next two animations are simply for fading elements in or out:
@keyframes fadeOut{ 0%{ opacity: 1; } 100%{ opacity: 0; } } @keyframes fadeIn{ 0%{ opacity: 0; } 100%{ opacity: 1; } }
slideLeft and slideRight will move an element from one side to the other by translating it:
@keyframes slideLeft{ 0%{ transform: translateX(120%); } 100%{ transform: translateX(0%); } } @keyframes slideRight{ 0%{ transform: translateX(-120%); } 100%{ transform: translateX(0%); } }
And moveUp will move an element up:
@keyframes moveUp{ 0%{ transform: translateY(0px); } 100%{ transform: translateY(-170px); } }
The last animation will simply “zoom in” and element by scaling it from 0 to 1:
@keyframes zoomIn{ 0%{ transform: scale(0); } 100%{ transform: scale(1); } }
And that’s all! I hope you enjoyed this experiment with me and find it inspiring!
This is really awesome!
Great manoela! once again, i’m amazed!
i’m going to practice a little bit more, ๐ thanks again!! ?
Beautiful examples, good job ๐
haha.. first… love the css3 page effects Mary
great as usual ๐
Wow, great. Keep going with nice articles like this. Thanks. Bravo!
Mary the ‘Flash Killer’ :p
omg this is so fuckin’ great, thanks a lot ๐
you rock, thanks for sharing ๐
Damn good! I love demo 2.. just like a flash..
Every day it’s christmas on this site ๐
Now – this is epic.
This is great stuff. I’m still can’t understand why so many people are creating stuff like this since it doesn’t work in IE. How can anyone use this in a project when so many people use IE?! There’s no fallback here.
That is amazing…thanks for showing us your talent ๐
Thank you all for your great feedback!
@Dan, there wouldn’t be any progress in this world if we kept thinking like that, right? ๐
The fallback is the conditional stylesheet for IE, just add your style there. If you want the animations, you could do that with JS. BTW, what makes you think that I am creating this to be used in a project? I’m just experimenting with CSS3 here ๐
Cheers, ML
That is sick!!!โฆi totally love it! Mary u are amazing!!!
Wow, I don’t think you’ve ever written a bad tutorial. Good work!
it is amazing! codrpos always come some outstanding ideas from the regular tools (CSS&Jquery)
awesome awesome awesome ๐
MARRY ME NAO!!11
lol all kidding aside. Great stuff. I WILL USE it on a real project. About IE, sorry folks. You can’t hold back the web because some asshole has IE 7 installed. It should be catered the other way around (majority of people use up to date browsers such as Chrome+FF).
Fantastic work!
Good work, very very good !!!!.
Congratulations !
——————————————-
Mary Lou in ascii !!!
/(-_-)\
!!
/!!\
!!
/ \
!!
A gift for you
——————————————-
Amazing demo! but please don’t bring back the splash pages ๐
Nice job
This rocks once again!
Nice!!!!!!
Muy bueno !!! lastima que funcione solo en Chrome. Saludos.
Hi,
Great demos, but…
In demo 3, did you mean to cut off the top of the text? If so, what was the intention of that?
Maybe I’m just picky, but I don’t think it looks good at all.
This is absolutely awesome! Thanks for that…
Very nice! simple and begginer friendly CSS3 templates. Thanks
Oh Mary Lou, you did it again. Super awesome.
Hey Mary, can i copy the whole code of your tutorial in my project ?
I love this!! Great tutorial, great message!
very nice, thank you mary
gr8 article i just love it
Thanks Mary! Awesome effect and usefull tutorial! ๐
Mary you are awesome again… splendid work…
This is absolutely great !!!! THANKS !!!
Just one word: AMAZING!
O.k., a second: THANKS!
haha, based on the title of this article, are you advocating the use of splash pages??!! Didn’t we leave that behind 4 to 5 years ago. Isn’t that one of the reasons Flash became so hated?
I love the fact that standards technologies such as CSS3 are more and more capable. But sometimes is seems like we’re starting to make the same poorly considered content and justifying it because we’re using a more acceptable technology.
Are there situations where this type of content is appropriate? Yes. I just hope we don’t all start throwing splash pages into our sites just because we can without plugins.
Really good! THX so much …
wooooooow
Hey Mary great work.You are really creative and talented.I m big fan of ur work.
It’s amazing, thanks;I have learnt how to use the property animation-fill-mode. But I don’t clearly understand how the value ‘none’ and ‘both’ work.
very nice…;)
Excellent!!! I hope to learn more about CSS3 through you guys…. also I’m amazed by your skills in jQuery, and I wonder how long did you take to understand the elaboration of plugins…
Hey, excelent!!! sory if my inglish is poor! but i have a question! in demo 2, how can i do to make de email text in works? which is de html code while i have to use to make it works; that e-mail to “x”mailbox the e-mail entered.
Sory for my poor inglish
sory, demo 1
Great work ๐ Thanks!
Beautiful effects, I’m really impressed ๐
nice ideas. why didn’t you use placeholder attribute at the first example btw?