Original Hover Effects with CSS3

The power of CSS3 is enormous and in this tutorial we will see how to exploit it in a very creative way. We are going to create some thumbnail hover effects with CSS3 transitions. On hover over a thumbnail, we will reveal some description of the thumbnail, using a different style in each example.

The power of CSS3 is enormous and in this tutorial we will see how to exploit it in a very creative way. We are going to create some thumbnail hover effects with CSS3 transitions. On hover over a thumbnail, we will reveal some description of the thumbnail, using a different style in each example.

Please note that this will only work properly in modern browsers that support the CSS3 properties in use.

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

The Markup

The structure of markup is very simple and intuitive. Create a container that will have our image and all the other infomation.

Inside the view insert an element with the class mask that will be responsible for our effects driven by CSS3 and inside it we will put a title, description and a link to the full image. (For some examples, we’ll need to add the mask element as a separate element and wrap the description in a devi with class content.)

<div class="view">  
     <img src="image.gif" />  
     <div class="mask">  
     <h2>Title</h2>  
     <p>Your Text</p>  
         <a href="#" class="info">Read More</a>  
     </div>  
</div>  

The CSS

After creating our markup we’re going to set our style.
We set the general rules for our class and then we are going to add a special class with the desired effect styles. We will omit the CSS3 vendor prefixes when showing the style.

.view {
    width: 300px;
    height: 200px;
    margin: 10px;
    float: left;
    border: 10px solid #fff;
    overflow: hidden;
    position: relative;
    text-align: center;
    box-shadow: 1px 1px 2px #e6e6e6;
    cursor: default;
    background: #fff url(../images/bgimg.jpg) no-repeat center center
}
.view .mask, .view .content {
    width: 300px;
    height: 200px;
    position: absolute;
    overflow: hidden;
    top: 0;
    left: 0
}
.view img {
    display: block;
    position: relative
}
.view h2 {
    text-transform: uppercase;
    color: #fff;
    text-align: center;
    position: relative;
    font-size: 17px;
    padding: 10px;
    background: rgba(0, 0, 0, 0.8);
    margin: 20px 0 0 0
}
.view p {
    font-family: Georgia, serif;
    font-style: italic;
    font-size: 12px;
    position: relative;
    color: #fff;
    padding: 10px 20px 20px;
    text-align: center
}
.view a.info {
    display: inline-block;
    text-decoration: none;
    padding: 7px 14px;
    background: #000;
    color: #fff;
    text-transform: uppercase;
    box-shadow: 0 0 1px #000
}
.view a.info:hover {
    box-shadow: 0 0 5px #000
}

And now we’ll look at the ten effects.

Example 1

OriginalHoverEffect01

Add the special class view-first to the element with the class view for this effect. We will be adding a special class to each example’s view element (view-first, view-second, view-third, etc.).

<div class="view view-first">  
       
</div>  

In this first example we will just use some basic transitions to create a nice hover effect.

.view-first img { 
    transition: all 0.2s linear;
}
.view-first .mask {
    opacity: 0;
    background-color: rgba(219,127,8, 0.7); 
    transition: all 0.4s ease-in-out;
}
.view-first h2 {
    transform: translateY(-100px);
    opacity: 0;
    transition: all 0.2s ease-in-out;
}
.view-first p { 
    transform: translateY(100px);
    opacity: 0;
	transition: all 0.2s linear;
}
.view-first a.info{
    opacity: 0;
	transition: all 0.2s ease-in-out;
}

And now comes the heart of our effect. When you move the mouse over the image, we can use the delay property to emulate simple animations. The transition-delay that we use in the hover class can be altered, to be differnt than the one in the normal class. In this example we did not use any delay in the normal class; but we added a delay on hover, which will make the transition start a bit later. Moving the mouse out, the default value of 0s will apply and the “reverse” will be quicker.

.view-first:hover img { 
	transform: scale(1.1);
} 
.view-first:hover .mask { 
	opacity: 1;
}
.view-first:hover h2,
.view-first:hover p,
.view-first:hover a.info {
    opacity: 1;
    transform: translateY(0px);
}
.view-first:hover p {
    transition-delay: 0.1s;
}
.view-first:hover a.info {
    transition-delay: 0.2s;
}

Example 2

OriginalHoverEffect02

In this second example we will add the special class view-second, but we will leave the element with the class mask empty and wrap the description in a div with the class content

<div class="view view-second">
	<img src="images/5.jpg" />
	<div class="mask"></div>
	<div class="content">
		<h2>Hover Style #2</h2>
		<p>Some description</p>
		<a href="#" class="info">Read More</a>
	</div>
</div>

Here the mask class will have different attributes to satisfy our effect, in fact we are going to apply the transform property (translate and rotate) and will make a square out of it. The description elements will be translated, i.e. moved so that we can slide them in on hover:

.view-second img { 	
	transition: all 0.2s ease-in;
}
.view-second .mask { 
	background-color: rgba(115,146,184, 0.7); 
	width: 300px;
    padding: 60px;
	height: 300px;
	opacity: 0;
	transform: translate(265px, 145px) rotate(45deg);
	transition: all 0.2s ease-in-out;
}
.view-second h2 {
    border-bottom: 1px solid rgba(0, 0, 0, 0.3);
    background: transparent;
    margin: 20px 40px 0px 40px;
    transform: translate(200px, -200px);
	transition: all 0.2s ease-in-out;
}
.view-second p { 
	transform: translate(-200px, 200px);
	transition: all 0.2s ease-in-out;
}
.view-second a.info { 
    transform: translate(0px, 100px);
	transition: all 0.2s 0.1s ease-in-out;
} 

For our hover effect we exploit the translate transformation in order to move our elements in place. The mask will also be rotated. The elements of the description will each come with a little delay:

.view-second:hover .mask { 
	opacity:1; 
	transform: translate(-80px, -125px) rotate(45deg);
}							  
.view-second:hover h2 { 
	transform: translate(0px,0px);
	transition-delay: 0.3s; 
}
.view-second:hover p { 
    transform: translate(0px,0px); 
	transition-delay: 0.4s;
}
.view-second:hover a.info { 
	transform: translate(0px,0px); 
	transition-delay: 0.5s;
}

Example 3

OriginalHoverEffect03

In this third example we will use the translate and rotate transforms to bring up our content:

.view-third img { 	
    transition: all 0.2s ease-in; 
}
.view-third .mask { 
	background-color: rgba(0,0,0,0.6);
	opacity: 0;
	transform: translate(460px, -100px) rotate(180deg);
	transition: all 0.2s 0.4s ease-in-out;
}
.view-third h2{
	transform: translateY(-100px);
	transition: all 0.2s ease-in-out;
}
.view-third p { 
	transform: translateX(300px) rotate(90deg);
	transition: all 0.2s ease-in-out;
}
.view-third a.info { 
	transform: translateY(-200px);
	transition: all 0.2s ease-in-out;
} 

These are the simple instructions that are applied on hover. Now we will reverse the appearing of the description elements by setting the transition-delay accordingly:

.view-third:hover .mask { 
	opacity:1; 
	transition-delay: 0s;							 
	transform: translate(0px, 0px);
}
.view-third:hover h2 { 
	transform: translateY(0px); 
	transition-delay: 0.5s; 
}
.view-third:hover p	{ 
    transform: translateX(0px) rotate(0deg);
	transition-delay: 0.4s;
}
.view-third:hover a.info { 
	transform: translateY(0px);
	transition-delay: 0.3s;
}

Example 4

OriginalHoverEffect04

Here in the fourth example we will perform a simple zoom out image and a zoom in of our content with rotation, all thanks to the scale transform. We set the transition-delay to 0.2s for the image style, but on hover we’ll say that it’s 0s. This will make it start immediately on hover, but delay it on mouse out.

.view-fourth img { 
	transition: all 0.4s ease-in-out 0.2s;
    opacity: 1;
}
.view-fourth .mask { 
	background-color: rgba(0,0,0,0.8);
	opacity: 0;
	transform: scale(0) rotate(-180deg);
	transition: all 0.4s ease-in;
    border-radius: 0px;
}
.view-fourth h2{
    opacity: 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.3);
    background: transparent;
    margin: 20px 40px 0px 40px;
	transition: all 0.5s ease-in-out;
}
.view-fourth p { 
	opacity: 0;
	transition: all 0.5s ease-in-out;
}
.view-fourth a.info { 
    opacity: 0;
	transition: all 0.5s ease-in-out;
} 

These are the simple instructions to get the effect – with CSS3 you can do everything ๐Ÿ™‚

.view-fourth:hover .mask { 
	opacity: 1; 
	transform: scale(1) rotate(0deg);
	transition-delay: 0.2s;
}								  
.view-fourth:hover img 	  { 
	transform: scale(0); 
    opacity: 0;
	transition-delay: 0s;
}						
.view-fourth:hover h2,
.view-fourth:hover p,
.view-fourth:hover a.info{
    opacity: 1;
    transition-delay: 0.5s;
}

Example 5

In this fifth example we will use the translate property along with the transition-timing-function ease-in-out in order to slide the content in from the left.

.view-fifth img {
	transition: all 0.3s ease-in-out; 
}
.view-fifth .mask { 
	background-color: rgba(146,96,91,0.3);
	transform: translateX(-300px);
	opacity: 1;
	transition: all 0.4s ease-in-out; 
}
.view-fifth h2{
    background: rgba(255, 255, 255, 0.5);
    color: #000;
    box-shadow: 0px 1px 3px rgba(159, 141, 140, 0.5);
}
.view-fifth p{
    opacity: 0;
    color: #333;
    transition: all 0.2s linear;
}

The hover effect will make the image slide to the right and the description come from the left, as if it’s pushing the image:

.view-fifth:hover .mask { 
	transform: translateX(0px);
}						
.view-fifth:hover img { 
	transform: translateX(300px);
	transition-delay: 0.1s;
}
.view-fifth:hover p{
    opacity: 1;
    transition-delay: 0.4s;
}

Example 6

OriginalHoverEffect06

In this example we will make the description come from the front, zooming out until its original size (scale from factor 10 to 1). The info button will slide in from the bottom (translate).

.view-sixth img { 
	transition: all 0.4s ease-in-out 0.5s; 
}
.view-sixth .mask{ 
	background-color: rgba(146,96,91,0.5);
	opacity:0;
	transition: all 0.3s ease-in 0.4s;
}
.view-sixth h2{
	opacity:0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.3);
    background: transparent;
    margin: 20px 40px 0px 40px;
    transform: scale(10);
    transition: all 0.3s ease-in-out 0.1s;
}
.view-sixth p { 
	opacity:0;
    transform: scale(10);
	transition: all 0.3s ease-in-out 0.2s;
}
.view-sixth a.info { 
	opacity:0;
    transform: translateY(100px);
	transition: all 0.3s ease-in-out 0.1s;
}

The reverse transition will be delayed in such a way that it looks smooth:

.view-sixth:hover .mask {  
	opacity:1; 
	transition-delay: 0s;
}																			 
.view-sixth:hover img { 
	transition-delay: 0s; 
}
.view-sixth:hover h2 { 
	opacity: 1;
    transform: scale(1);
	transition-delay: 0.1s;
}
.view-sixth:hover p { 
	opacity:1; 
    transform: scale(1);
	transition-delay: 0.2s;
}
.view-sixth:hover a.info { 
	opacity:1;
    transform: translateY(0px);
	transition-delay: 0.3s;
}

Example 7

OriginalHoverEffect07

In this seventh example the idea is to rotate the image to the center and scale it down. Then the description comes rotating from up with the description content following.

.view-seventh img{
    transition: all 0.5s ease-out;
	opacity: 1;
}
.view-seventh .mask { 
	background-color: rgba(77,44,35,0.5);
    transform: rotate(0deg) scale(1);
	opacity: 0;
	transition: all 0.3s ease-out;
    transform: translateY(-200px) rotate(180deg);
}
.view-seventh h2{
    transform: translateY(-200px);
	transition: all 0.2s ease-in-out;
}
.view-seventh p { 
    transform: translateY(-200px);
	transition: all 0.2s ease-in-out;
}
.view-seventh a.info { 
    transform: translateY(-200px);
	transition:  all 0.2s ease-in-out;
} 

On hover we add a delay for the desciption elements. This will show us the rotating image first and then the description will come into the picture. In the reverse transition, everything will disappear immediately and we’ll see the image rotate back:

.view-seventh:hover img{
    transform: rotate(720deg) scale(0);
	opacity: 0;
}
.view-seventh:hover .mask { 
	opacity: 1;  
    transform: translateY(0px) rotate(0deg);
    transition-delay: 0.4s;
}																						
.view-seventh:hover h2 { 
    transform: translateY(0px);
	transition-delay: 0.7s;
}
.view-seventh:hover p { 
	transform: translateY(0px);
	transition-delay: 0.6s;
}
.view-seventh:hover a.info { 
    transform: translateY(0px);
	transition-delay: 0.5s;
}

Example 8

OriginalHoverEffect08

In this eighth example we’ll use an animation and recreate a bounce effect. The description will bounce in from the top.

.view-eighth .mask { 
	background-color: rgba(255, 255, 255, 0.7);
	top: -200px;
	opacity: 0;
	transition: all 0.3s ease-out 0.5s;
}
.view-eighth h2{
    transform: translateY(-200px);
	transition: all 0.2s ease-in-out 0.1s;
}
.view-eighth p { 
    color: #333;
    transform: translateY(-200px);
	transition: all 0.2s ease-in-out 0.2s;
}
.view-eighth a.info { 
    transform: translateY(-200px);
	transition:  all 0.2s ease-in-out 0.3s;
} 

We’ll add the animation to the mask element and define some fitting delays for the onset of the description elements:

.view-eighth:hover .mask { 
	opacity: 1; 
	top: 0px; 
	transition-delay: 0s; 
    animation: bounceY 0.9s linear;
}																						
.view-eighth:hover h2 { 
    transform: translateY(0px);
	transition-delay: 0.4s;
}
.view-eighth:hover p { 
	transform: translateY(0px);
	transition-delay: 0.2s;
}
.view-eighth:hover a.info { 
    transform: translateY(0px);
	transition-delay: 0s;
}

To recreate a true bounce effect we use the translateY, as you can see there are a couple of frames, in order to make the effect:

@keyframes bounceY {
    0% { transform: translateY(-205px);}
    40% { transform: translateY(-100px);}
    65% { transform: translateY(-52px);}
    82% { transform: translateY(-25px);}
    92% { transform: translateY(-12px);}
    55%, 75%, 87%, 97%, 100% { transform: translateY(0px);}
}

Example 9

OriginalHoverEffect09

In this example, we will use two mask elements to slide them in from the bottom right and the top left:

<div class="view view-ninth">
	<img src="images/11.jpg" />
	<div class="mask mask-1"></div>
	<div class="mask mask-2"></div>
	<div class="content">
		<h2>Hover Style #9</h2>
		<p>Some Text</p>
		<a href="#" class="info">Read More</a>
	</div>
</div>

The two masks will have a different translation and a transfrom origin. Also, we’ll set one to be aligned at the top and the other at the bottom:

.view-ninth .mask-1,
.view-ninth .mask-2{
	background-color: rgba(0,0,0,0.5);
    height: 361px;
    width: 361px;
	background: rgba(119,0,36,0.5);
	opacity: 1;
    transition: all 0.3s ease-in-out 0.6s;
}
.view-ninth .mask-1 { 
    left: auto;
    right: 0px;
    transform: rotate(56.5deg) translateX(-180px);
    transform-origin: 100% 0%;
}
.view-ninth .mask-2 { 
    top: auto;
    bottom: 0px;
    transform: rotate(56.5deg) translateX(180px);
    transform-origin: 0% 100%;
}

The content will be styled in a way that it looks like as if it’s coming out as a tiny slice through the touching edges of the two masks:

.view-ninth .content{
    background: rgba(0,0,0,0.9);
    height: 0px;
    opacity: 0.5;
    width: 361px;
    overflow: hidden;
    transform: rotate(-33.5deg) translate(-112px,166px);
    transform-origin: 0% 100%;
    transition: all 0.4s ease-in-out 0.3s;
}
.view-ninth h2{
    background: transparent;
    margin-top: 5px;
    border-bottom: 1px solid rgba(255,255,255,0.2);
}
.view-ninth a.info{
    display: none;
}

On hover, we’ll make the content come out from the slot and make the masks touch at their edges:

.view-ninth:hover .content{
    height: 120px;
    width: 300px;
    opacity: 0.9;
    top: 40px;
    transform: rotate(0deg) translate(0px,0px);
}
.view-ninth:hover .mask-1,
.view-ninth:hover .mask-2{
	transition-delay: 0s;
}
.view-ninth:hover .mask-1{
    transform: rotate(56.5deg) translateX(1px);
}
.view-ninth:hover .mask-2 {  
    transform: rotate(56.5deg) translateX(-1px);
}

We are setting the transition-delay for the masks in such a way, that when we hover, the transition happens instantly. But when moving out with the mouse, the delay will be longer, as if its “waiting” for the content to move back into the slot.

Example 10

OriginalHoverEffect10

In the last example, we will zoom in the image and make it fade out while bringing the descpription to the front. We can do that by using the scale transform and setting the opacity level:

.view-tenth img { 
	transform: scaleY(1);
	transition: all 0.7s ease-in-out;
}
.view-tenth .mask { 
    background-color: rgba(255, 231, 179, 0.3); 
    transition: all 0.5s linear;
    opacity: 0;
}	
.view-tenth h2{
    border-bottom: 1px solid rgba(0, 0, 0, 0.3);
    background: transparent;
    margin: 20px 40px 0px 40px;
    transform: scale(0);
    color: #333;
    transition: all 0.5s linear;
    opacity: 0;
}
.view-tenth p {
    color: #333;
    opacity: 0;
    transform: scale(0);
    transition: all 0.5s linear;
}
.view-tenth a.info { 
    opacity: 0;
    transform: scale(0);
    transition: all 0.5s linear;
}

On hover, we’ll simply scale the image up and fade it out by decreasing its opacity to 0:

.view-tenth:hover img { 
	transform: scale(10);
    opacity: 0;
}
.view-tenth:hover .mask { 
	opacity: 1;
}																			 
.view-tenth:hover h2,
.view-tenth:hover p,
.view-tenth:hover a.info{ 
    transform: scale(1);
    opacity: 1;
}

Conclusion

CSS3 has a really great potential for creating nice effects. Soon, we’ll hopefully be able to avoid the use of JavaScript for simple effects and rely 100% on CSS, in all browsers.
I hope that you liked these experiments, but above all I hope that they can inspire you for your projects.

Alessio Atzeni

Alessio Atzeni, based in Rome, Italy, is a dedicated web designer and front-end developer with a passion for CSS3. He specializes in CSS and JavaScript web development, and building search engine friendly websites. For more front-end web development tutorials and CSS3 experiments, check out his web design blog.

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

Fresh news, inspo, code demos, and UI animationsโ€”zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 136

Comments are closed.
  1. Hi i heave a question:
    These css3 effects work fine in local view (im using dreamweaver 5.5) but it doesn’t work when i upload the files and watch online. It cant be missing style declarations because that would show in local view. What am i missing here? Im using firefox 7,0,1

  2. Oh wait! cancel that! I figured it out, i just screwed up the style sheets ๐Ÿ™‚
    never drink while coding kids

  3. Great effects. And no javascript! Thanks!

    I know, it is not a question of the effect, but does someone have a good solution for headline/descriptions above or below the photos?

    That would be great!

    Regards
    George

  4. O.k., I made it another way a build transparent boxes over the photos.

    Fot those who are interested, here is the html/css code.

    headline

    Headline
    description
    Read more

    .headline {
    float: left;
    width: 260px;
    height: 40px;
    background-color: rgba(255,255,255, 0.7);
    -ms-filter: “progid: DXImageTransform.Microsoft.Alpha(Opacity=0.7)”;
    filter: alpha(opacity=0.7);
    opacity: 0.7;
    position: absolute;
    margin-top: 0px;
    display: inline;
    margin-left: -130px;
    z-index: 1;
    margin-top: 20px;

    }

    .headline h1 {
    font-size: 18px;
    line-height: 20px;
    text-decoration: none;
    padding-top: 10px;
    text-transform: uppercase;
    color: #000;
    }

    Regards
    George

  5. o.k., sorry, no html code possible in the comments. But it is just a span class .headline and a h1 before the img tag.

    Regards
    Joerg

  6. A fix i discovered for the ‘flickering text’ – you will notice it only DURING the transitions – go have a look – is to add:

    -webkit-perspective: 1000; to your root containing element.

    Hope that helps!

  7. Great tutorial. I think I will be using number 10 as its the one that degrades the best down to IE7.

    @HANS They work in Firefox, Chrome, Safari and IE9. IE7 and IE8 don’t like them but example 10 works minus the animation.

  8. These are great. I just can’t get mine to work. I liked #5 and I placed the html in my site and the css in my style sheet. Maybe it doesn’t work for my version of WP…It seems pretty easy enough. What am I doing wrong, I wonder…The design portion is there but no pictures are switching out.

  9. @Toni strange, wordpress is not the problem, check if you forgot to add some class…

    @Jm for IE10 this transition should work with the prefix -ms-, while for older versions you could recreate the same effect with jQuery.

  10. Ok, one last question. It does not degrades nicely on handhelds. I tried on an iPhone and images are not clickable, there is no way to reveal the hidden text in sample #10. Any idea how I could easily fix that?

  11. Can this technique be used on commercial project for example ThemeForest? What licence is that? GNU GPL, MIT, CC?

  12. Awesome!

    What about browser compatibility? Especially, what will happen on old browsers? Graceful degradation?

  13. It works on all browsers, if the browser does not support the transitions the description appear immediately without any animation.

  14. Cool! How could we make WordPress posts have these effects? (with image posts/gallery i mean)…

  15. Is it possible to modify this in a way so that the container works in a resonsive design? Meaning that it will change size depending on browser width and not just cut off? It looks awesome and I want to incorporate it in a fluid website design. Thanks!

  16. You are AWESOME to share. And a great writer/teacher too. Instructions are quick and easy to comprehend. Thank you,

  17. I love this effect and have been trying to get it to work and running into some problems. Not sure if you can take a look at this and maybe point me int eh right direct. http://www.awingthing.com/dev/about-us/

    As you can see the hover works, but the animation is not. Any thoughts on what I’m missing?

  18. NM. I figured it out. I’m new to this stuff and didn’t have the common files. I went right off of the instructions on this page.

  19. @shawn: where exactly do we have to place the code that you are saying:

    -webkit-perspective: 1000;

    thanks and this will be a big leap for this project.

  20. Love these effects and have made demo 1 work perfectly, apart form 1 small issue. It seems the text (h2 and ) turn to bold once the text animates in. Any ideas how i can get the font to stay crisp?

  21. What an amazing tutorial! It works perfectly, except one thing: try ‘hovering’ or clicking on the images from an iPhone – nothing happens! Not even if you wrap the image with a direct link. How come? Is there a way around?

    Please help me with this, it gotta work on iPhone…

    Thanks!

  22. When I hover some of the images, a giant black overlay appears like a millisecond (h/w 100%). Very annoying (opposite flash light effect). Are you aware of this little bug? I am using Chrome 16.0.912.75 on OSX 10.6.8. Big thumb up for sharing demonstrating these awesome ‘flash-a-like’ effects.

  23. Just noticed the chrome flickered when animation started. Add this: * {-webkit-backface-visibility: hidden;} and it worked. Much better and great job!

  24. Hello

    I am experiencing on chrome 16.0.912.77, on demos which are using overlays or zooming out in not slide flickering the screen and some people has blue 1, 2, 4, 6, 7, 8 demos, on Snow Leopard in Chrome flickers the screen a lot on Lion less. I am not alone, I tested with more people. Do you know what can it be I have also video of that. thanks

  25. Nevermind, disregard comment above:

    @Aaron Hall
    Add this: * {-webkit-backface-visibility: hidden;} and it worked. Much better and great job!

    Thanks a lot! It works ๐Ÿ™‚