Standard and retina display sprites with compass – how to

First of all, if you are not using sass/compass yet – you definitely should start right now. There are plenty of resources on how to install compass on mac or PC. Myself, I’m using a mac app “Codekit”.
One of the of compass features that are especially compelling is “spriting”. With compass you simply place all your images in a folder and import them into your stylesheet.
In this post I’ll share with how I prepare my sprites in two “versions” for standard and retina display.
Click on the image below to see the demo (check it on your retina display).

Spriting with compass for standard and retina display

Let’s follow two simple examples :

Example 1 – button

Let’s prepare a button with three states normal, hover and target. I prepare the three states of buttons in two sizes (normal and doubled for retina display). I save the separate .pngs in two folders : button and button2x.
The button folder will contain : button.png, button-hover.png and button-target.png. Identically button2x will contain : button.png, button-hover.png and button-target.png.

You can create and work with sprites compass in two ways. The first one would be the import-based approach :
@import "button/*.png"; @include all-button-sprites;
You can also specify a configurable variable before importing the sprite.

  


/* we'll use some mixins included in Compass Sprites Base */
@import "compass/utilities/sprites/base";
/* Set the variable
we'll have to assign background : $tut-sprites and background : $tut-sprites2x somewhere so that the sprite files were created */
$tut-sprites: sprite-map("button/*.png");
$tut-sprites2x: sprite-map("button2x/*.png");
/* I define a new mixing sprite-selectors2x, a retina version of sprite-selectors included in Compass Sprites Base */
/* We need to make sure that each sprites have a good background position - that's because the order of sprites in normal and retina versions is not necessarily the same */  
@mixin ph-sprite-selectors2x($map, $map2x, $sprite-name, $full-sprite-name, $offset-x: 0, $offset-y: 0) {	
  @each $selector in $sprite-selectors {
    @if sprite_has_selector($map2x, $sprite-name, $selector) {
      &:#{$selector}, &.#{$full-sprite-name}_#{$selector}, &.#{$full-sprite-name}-#{$selector} {
	@if (nth(sprite-position($map2x, #{$sprite-name}_#{$selector}),2) != 2*nth(sprite-position($map, #{$sprite-name}_#{$selector}),2) ) {
           background-position: $offset-x round(nth(sprite-position($map2x, #{$sprite-name}_#{$selector}, 0, 2*$offset-y), 2)/ 2);
	}
      }
    }
  }
}
/* Below the mixin that sets the proper background-positions, adds dimension (if desired) for both normal and retina display, */
/* Again we have to check whether the sprites order hasn't changed between normal and retina and update the background position if necessary */
@mixin ph-sprites($map, $map2x, $_item, $dimensions:false, $offset-x: 0, $offset-y: 0) {
	
	background-position: sprite-position($map, $_item, $offset-x, $offset-y );
	@if $dimensions {@include sprite-dimensions($map, $_item);} 
	@include sprite-selectors($map, $_item, $_item, $offset-x, $offset-y);
		@media only screen and (-webkit-min-device-pixel-ratio : 1.5), only screen and (min-device-pixel-ratio : 1.5)	{   
		@if (nth(sprite-position($map2x, $_item),2) != 2*nth(sprite-position($map, $_item),2) ) {
		}
                background-position: $offset-x round(nth(sprite-position($map2x,  $_item, 0, 2*$offset-y), 2)/ 2);
                background-size:image-width(sprite-path($map)) image-height(sprite-path($map));
		@include ph-sprite-selectors2x($map, $map2x, $_item, $_item, $offset-x, $offset-y);
	} 
}
/* Now we'll apply the ph-sprites mixing  to the .button class */
.button {
background: $tut-sprites;
	 @media only screen and (-webkit-min-device-pixel-ratio : 1.5), only screen and (min-device-pixel-ratio : 1.5) 
		{
			background:$tut-sprites2x;
		}
	@include ph-sprites($tut-sprites,$tut-sprites2x, button, true);
}

The above will compile to (note that two files have just been created : button-se4c41ebe77.png and button2x-s8a4e15a939.png)


.button {
  background: url('../images/button-se4c41ebe77.png');
  background-position: 0 -96px;
  height: 48px;
  width: 104px;
}
@media only screen and (-webkit-min-device-pixel-ratio : 1.5), only screen and (min-device-pixel-ratio : 1.5) {
    .button {
      background: url('../images/button2x-s8a4e15a939.png');
     } 
}
.button:hover, .button.button_hover, .button.button-hover {
    background-position: 0 0; 
}
.button:target, .button.button_target, .button.button-target {
    background-position: 0 -48px; 
}
@media only screen and (-webkit-min-device-pixel-ratio : 1.5), only screen and (min-device-pixel-ratio : 1.5) {
    .button {
      background-size: 104px 144px; 
    } 
}

The corresponding markup is as follows


<!DOCTYPE html>
<html lang="en">
<head>
<link href='http://fonts.googleapis.com/css?family=Homenaje' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Sansita+One' rel='stylesheet' type='text/css'>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sprites with Compass - tutorial</title>
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>

<body>
	<div>
		<h2>Sprites created with compass</h2>
		<a href="" type="submit" class="button" name="waiting">
		        Back
		</a>
		<a  href="#" class="button button-hover" title="hover">
		        Hover
		</a>
		<a  href="#" class="button button-target" title="clicked">
		        Clicked
		</a>
		<ul class="social">
			<li><a class="icons-twitter" href="http://twitter.com/pehaa">Twitter</a></li>
			<li><a class="icons-dribbble" href="http://dribbble.com/pehaa">Dribbble</a></li>
			<li><a class="icons-pinterest" href="http://pinterest.com/pehaa">Pinterest</a></li>
			<li><a class="icons-deviantart" href="http://pajkabajka.deviantart.com/">DA</a></li>
			<li><a class="icons-flickr" href="http://www.flickr.com/photos/pajkabajka/">Flickr</a></li>
		</ul>
		<p>Buttons by <a title="created in Vains Faktory by Joe Vains" href="http://vainsfaktrory.com" target="_blank">Joe Vains</a></p>
	</div>
</body>
</html>

Example 2 – social icons

We can use the same mixing for the simple social icons :


$icons: sprite-map("icons/*.png", $position: 100%, $spacing: 15px, $repeat: no-repeat);
$icons2x: sprite-map("icons2x/*.png", $position: 100%, $spacing: 30px, $repeat: no-repeat);
a {
    background-repeat: no-repeat;
    background-image:$icons;
    @media only screen and (-webkit-min-device-pixel-ratio : 1.5), only screen and (min-device-pixel-ratio : 1.5) {
      background-image:$icons2x;
    }
    @each $_icon in  twitter, dribbble, pinterest, deviantart, flickr {
	&.icons-#{$_icon} {
	  @include ph-sprites($icons,$icons2x, #{$_icon}, false, 7px, 7px);
	}
    }
}

Create a fancy responsive image-on-hover effect

In this tutorial we will create a fancy image-on-hover effect. We’ll use pure css3 and provide a jQuery solution for the browsers that do not support opacity and transitions. We will also take care that it works responsively.

Two version of an image

Download the source files

Fancy responsive image-on-hover effect
.zip 0.2MB

Step 1 : Photoshop

We have to prepare two versions of the image : the image we want to see on hover and its desaturated copy. Mine are 845px x 515px.

Two version of an image

Step 2 : Let’s start with the html markup

..
<div id="wrap">
<ul>
   <li>
      <div>
          <img src="img/tut1_desaturated.jpg"/>
          <span class="shadow"></span>
          <img class="onhover" src="img/tut1_color.jpg"/>
      </div>
   </li>
</ul>
</div>

Step 3: Basic styles

We start our stylesheet with a basic reset.

html, body, div, span, h1, h2,  p, a,  ul, li, img
{margin: 0; padding: 0;
border: 0; outline: 0;
font-size: 100%;background: transparent;}
ul {list-style: none;}

The main containing element #wrap is centered up and given the specific width 865 px = 845px (image size) + 2x10px (borders size).
The div that contains the images is given position:relative (to properly position the two versions of the image) and overflow hidden (we will size up and rotate our images and we want to hide the exceeding parts).

#wrap { width: 865px; margin: 0 auto;}
ul {margin-top:50px; }
li div {width:845px; height:515px; overflow:hidden; position:relative;
border:10px solid white; box-shadow: 0 2px 5px  rgba(0,0,0,.4);}

Step 4: Grayscale to color transition (see demo)

The img element is positioned relatively, the colored version (.onhover) is given 0 opacity and absolute position. When the containing div is being hovered over the opacity of .onhover element changes to 1. To make the transition smooth we apply the transition property to img. (For simplicity I decided to omit all vendor prefixes).

img {position:relative; top:0;left:0;
transition:all 1.5s .5s; }
img.onhover {opacity:0;position:absolute;}
li div:hover img.onhover {opacity:1;}

To deepen the effect of transition between the normal and hover state we will add a fading out inner shadow (span.shadow):

.shadow {position:absolute; top:0; left:0; opacity:1; background:transparent;
width:100%; height:100%;
box-shadow: inset 0 0 60px 20px rgba(37,27,23,.5);
transition:opacity 1.5s .5s;}
li div:hover .shadow {opacity:0;}

Step 5: Let’s add scaling and rotation (see demo)

We just have to add the transform property, specify the transform origin as well as the transform parameters in hover state.

img {position:relative; top:0;left:0;
transition:all 1.5s .5s;
transform: rotate(-4deg) scale(1.2);
transform-origin:50% 50%;}

li div:hover img {transform: scale(1) rotate(0);}

Step 6: And what if we want it responsive ? (see demo)

First let’s modify a little bit the style of #wrap and the li div to keep them flexible. In the latter case we just no longer specify the height and width of the element.

#wrap { max-width: 865px; margin: 0 auto; width:95%;}
li div { overflow:hidden; position:relative;
border:10px solid white; box-shadow: 0 2px 5px rgba(0,0,0,.4);}

We have also to modify the styling of the img element – we add three new properties to the img element.

img {max-width:auto; vertical-align:bottom; width:100%;}

Step 7: jQuery solution

We will add a jQuery solutions for IE.

<!--[if lt IE 9]><script>
<script src="http://code.jquery.com/jquery-latest.js"></script>
	$(document).ready(function() { 
           $('.onhover').hide();
$('li div').hover(function(){
$(this).find('.onhover').fadeIn(1000);
},function(){
$(this).find('.onhover').fadeOut(1000);
})
})
</script><![endif]-->

You can also go further and recreate the full transition with jQuery animate function.

And that’s it. I hope you got inspired by this example – it’s your turn to play with css transitions. Enjoy !

Intriguing animate-on-scroll effect – jQuery tutorial

I suppose that I was not the only one to become speechless in front of the Nizo for iPhone website.
In this tutorial we try to recreate the intriguing scrolling effect. We’ll go for simplicity : 5 objects to animate and linear movement, no easing. The basis that opens the door for further elaboration.

Click here to see the demo.
My herb garden preview

Download the source files

My herb garden
.zip 0.4MB

We’ll start with the html structure :

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>My herb garden</title>
</head>
<body>
<div id="wrap_out">
  <div id='wrap'>
    <header>
      <h1>My <em>herb</em> garden</h1>
      <p>Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum id ligula porta felis euismod semper.</p>
    </header>
    <div id="separation">
      <div>Scroll <em>down</em></div>
      <img src="images/herbes.jpg" width="592" height="350" alt="Herbes"> </div>
    <section>
      <div  id="coriander" class="element">
        <div>coriander</div>
        <img src="images/coriander1.jpg" width="286" height="232" alt="Coriander">
        <p>Cras mattis consectetur purus sit amet fermentum. Cras mattis consectetur purus sit amet fermentum. Cras mattis consectetur purus sit amet fermentum.</p>
      </div>
      <div  id="rosemary" class="element">...</div>
      <div  id="lemonbalm" class="element">...</div>
      <div  id="chives" class="element">...</div>
      <div  id="basil" class="element">...</div>
    </section>
    <footer> <a href="http://pehaa.com"> by <em>PeHaa</em> 2011</a> </footer>
  </div>
</div>
</body>
</html>

The document is composed of 4 elements header, #separation, section and footer, contained within two divs : #wrap_out and #wrap.
The stylesheet begins with a simple css reset and the @font-face declaration

body, div, h1, h2, form, fieldset, input, textarea, footer, p, img {
	margin: 0; padding: 0; border: 0; outline: none;
}
a { text-decoration:none; color: #fff;}

 @font-face {
 font-family: 'DeibiRegular';
 src: url('deibi-webfont.eot');
 src: url('deibi-webfont.eot?#iefix') format('embedded-opentype'),  url('deibi-webfont.woff') format('woff'),  url('deibi-webfont.ttf') format('truetype'),  url('deibi-webfont.svg#DeibiRegular') format('svg');
 font-weight: normal;
 font-style: normal;
}

Right now, the important point is to set width : 100% and overflow-x: hidden for the #wrap_out. The #wrap element centers the content of the page.
section is positioned relatively and the animated herbs (class="element") are positioned absolutely.
Let’s continue with our stylesheet :

body { 
	font-family:'DeibiRegular', Helvetica, Arial, sans-serif;
	background:#f2f2f2 url('images/bg.jpg');
	color: #fff; width:100%;
}
#wrap_out {width:100%; overflow-x:hidden;}
#wrap {width: 960px; margin: 0 auto; z-index:1;position:relative;}


header {display:block;z-index:2 position:relative;}
header p {display:block; font-size:30px; padding: 70px 60px 0px;}
h1 {text-align:center;font-size:130px; margin-top: 30px; text-shadow: 0 0 60px #889473;}
h1 em {color: #f5f187;font-style: normal;}

#separation {margin: 0 auto;width: 592px;z-index:-1;position:relative;}

section {position:relative; margin-top: 120px;display:block}

.element { position:absolute; display:block;}
.element#coriander {top:0px; left:30px; width: 286px; height: 272px;}
.element#rosemary {top:40px; left: 335px; width: 370px; height: 183px;}
.element#chives {top : 0px; right:30px; width: 197px; height: 514px;}
.element#lemonbalm {left: 30px; top:280px; width:265px; height: 233px;}
.element#basil {right: 255px; top:250px; width:368px; height: 263px;}

footer {margin-bottom: 10px;text-align:center;font-size: 30px; display:block}

The idea is to encourage the visitor to scroll down by positioning the #separation element at the bottom of the page. We want the #separation to stay there when the window is resized but to move up when we start to scroll down. A possible way to do that is to make the height of the header element dependent on the height of the window browser :

$(document).ready(function () {
    var myHeight;

    function init() {
        myHeight = $(window).height();
        $('header').css('height', myHeight - 300);
    }
    init();
    $(window).resize(function () {
        init();

    });
})

To animate the .element we’ll go simple and use a linear function to move it from its initial position to its target position. We assign four parameters (its initial and final coordinates) to each element :

$('.element').each(function(i) {
			var myElement =$(this);
			
			
				switch (i)
				{ case 0 : 
					myElement.data('params', {top0 : -1300, x0 : -2600, top1: $(this).css('top'), x1: $(this).css('left')}); 
					break; 
				case 1 : 
					myElement.data('params', {top0 : 0, x0 : -930, top1: $(this).css('top'), x1: $(this).css('left')}); 
					break; 
				case 2 : 
					myElement.data('params', {top0 : 280, x0 : -1030, top1: $(this).css('top'), x1: $(this).css('left')});
					break; 	
				 case 3 : 
					myElement.data('params', {top0 : -1200, x0 : -2330, top1: $(this).css('top'), x1: $(this).css('right')}); 
					break; 
				case 4 : 
					myElement.data('params', {top0 : 250, x0 : -530, top1: $(this).css('top'), x1: $(this).css('right')}); 
					break; 
				}
			});

What happens when we scroll ? The top property of each element and the left (for coriander, rosemary and lemon bald) or right (for chives and basil) changes as a function of the scroll position :

 
$(window).scroll(function () {
var s_max = myHeight / 2 + 500;
    function move(p0, p1, s) {
        return Math.min((-p0 + p1) / s_max * s + p0, p1);
    }
	
    var scrollTop = parseInt($(window).scrollTop());
    $('.element').each(function (i) {
       

        var myX = move($(this).data('params').x0, parseInt($(this).data('params').x1), scrollTop),
            myY = move($(this).data('params').top0, parseInt($(this).data('params').top1), scrollTop);
        
if (i < 3) {
            $(this).stop().css({
                left: myX + 'px',
                top: myY + 'px'
            })
        } else {
            $(this).stop().css({
                right: myX + 'px',
                top: myY + 'px'
            })
        }
    })
})

move is a function of the scroll value and has two parameters : initial (p0) and final (p1) position of an element.
Before we start scrolling, s = 0, move is equeal to p0. When scroll reaches s_max, the value of move is p1. The min operator prevents further movement.
As I said this is one of the simplest possible solutions.
What is s_max ? I wanted the animation to finish once the elements are verticaly centered in the middle of the window (I’m not pixel perfect here).
Where is that point ? Imagine that we don’t animate our elements and that they are in their final positions. Notice that we have to scroll down 500px (see the scheme below), to see the top of the second row of our herbs. If we scroll down a half height of a window more we will see them in the middle.
My herb garden preview
We want to be sure that the page is high enough so that the elements could reach their final positions. To assure that we will make the property height of section dependent on the height of the browser window, in this case we need to scroll $(window).height/2 + 500. We have 240px above the section (120px + 120px). The minimum height of section is then $(window).height/2 + 260. We add a line to the init function

function init() {
    myHeight = $(window).height();
    $('header').css('height', myHeight - 300);
    $('section').css('min-height', Math.max(myHeight / 2 + 260, 600));
}

It was tested in Safari, Firefox, Chrome, Opera, IE7 and IE8. It works in the last two if you don’t forget to add

<!--[if IE]>
	<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

I hope you find it useful. Please bookmark and share.
Let me know what you think – I’m looking forward to your comments. Thanks.

postcard from Paris – css3 keyframes animations in use

I decided to explore the area of css3 keyframes animations. The idea was simple – to create a sort of virtual postcard. I live in Paris so obviously I send you my greetings from Paris :). Click here or on the image to view the animation demo.
Postcard from Paris css3 reframes animation preview

Download the source files

(.psd file included)
Postcard from Paris
.zip 1.9MB

The css3 animations are supported by : Chrome 2+, Safari 4+, Firefox 5+, iOS Safari 3.2+ and
Android 2.1+ (source Smashing Magazine).
We are going to animate 3 elements : the clouds (there are three layers of clouds), the rotating phare light and the Eiffel Tower sparkling.

The html structure is very simple :

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Greetings from Paris</title>
</head>
<body>
   <div id="wrap">
      <h1>Bonne Nuit <em>PARIS !</em></h1>
      <div id="phare"></div>		
      <div id="eiffel"></div>
      <div id="eiffel_wrap">
         <div id="sparkling1"></div>
         <div id="sparkling2"></div>
      </div>	
      <div id="roofs"></div>
      <footer>by PeHaa, Paris 2011</footer>
   </div>
</body>
</html>

We will use the following images (I will discuss the sparkling effect a little bit later)
used images
Let’s start to complete the css stylesheet :
ccs part 1

Animating clouds

To animate the three layers of clouds independently we use the following keyframes. (Notice that each time I use the -webkit- and -moz- prefixes).

/* will be applied to #wrap that has 3 backgrounds layers */

	@-webkit-keyframes wind  {
	         0% {background-position: 0px 200px,0px 350px, left top;}
			50% {background-position:  500px 40px,600px 450px, left top;}
			100% {background-position: 1000px 200px,1200px 350px, left top}
	}
	
	@-moz-keyframes wind  {
	         0% {background-position: 0px 200px,0px 350px, left top;}
			50% {background-position:  500px 40px,600px 450px, left top;}
			100% {background-position: 1000px 200px,1200px 350px, left top}
	}

/* will be applied to #roofs that has 2 backgrounds layers */
	
	@-webkit-keyframes wind1 {
	         0% {background-position: 100px 250px, left bottom;}
			50% {background-position:  650px 150px, left bottom;}
			100% {background-position: 1300px 250px, left bottom}
	}
	
	@-moz-keyframes wind1 {
	         0% {background-position: 100px 250px, left bottom;}
			50% {background-position:  650px 150px, left bottom;}
			100% {background-position: 1300px 250px, left bottom}
	}

This way we have defined the property of background-position for the beginning, middle and end of our animation. Next we add :

#wrap {-webkit-animation: wind 80s linear infinite; 
       -moz-animation: wind 80s linear infinite;}
#roofs {-webkit-animation: wind 80s linear infinite;
       -moz-animation: wind 80s linear infinite; }

to associate the animations with the proper elements and to define the duration, timing-function and iteration count, respectively (I use the shorthand notation).

Animating phare light

This time we are going to simultaneously animate the opacity and rotate the phare light with the rotation origin in its top center point (as in the image above).

	@-webkit-keyframes phare {
	         0% { -webkit-transform:rotate(0deg); opacity:0} 
		50% { -webkit-transform:rotate(180deg); opacity:1} 
	        100% { -webkit-transform:rotate(360deg); opacity:0;}
	}
        #phare {-webkit-transform-origin: center top; 
	        -webkit-animation: phare 15s linear infinite;}

(here and further, repeat the same with -moz- prefixes).

Adding sparkles

We will use two different images with sparkling effect
Sparkling
Below is the styling :

#eiffel_wrap { position:absolute; width:240px; 
              height:462px; right:10px; top: 180px; opacity:0;}
#sparkling1 { position:absolute; background: url('images/sparkling1.png') no-repeat; 
              width:240px; height:462px; opacity:0;}
#sparkling2 { position:absolute; background: url('images/sparkling2.png') no-repeat; 
              width:240px; height:462px;  opacity:0;}

We will animate the #eiffel_wrap, #sparkling1 and #sparkling2.

@-webkit-keyframes sparkling {
		0% {opacity:0;}
		50%{opacity:1;}
		100% {opacity:0;}
	}

The idea is to use the sparkling animation to turn out and in the #sparkling1 and #sparkling2 elements within the 0.4s cycle, with the first in/out when the second is out/in. To achieve that we will delay the sparkling animation of 0.2s on #sparkling1.

>
#sparkling1 {-webkit-animation: sparkling .4s .2s  infinite;}
#sparkling2 {-webkit-animation: sparkling .4s  infinite;}

In Paris this beautiful evening spectacle may be seen for several minutes every full hour. We will use the #eiffel_wrap element and eiffel_wrap animation to recreate this effect (not literarily though – I will not make you wait an hour long).

#eiffel_wrap { -webkit-animation: eiffel_wrap 30s 1s  infinite;} 
@-webkit-keyframes eiffel_wrap {
		    0% {opacity:1;-webkit-animation-timing-function: steps(1);}
			40%{opacity:0;}
			100% {opacity:0;}
			}

With -webkit-animation-timing-function: steps(1); the transition is instantaneous with no fading out effect.

And here we are.
I hope you found this tutorial useful and got inspired. Please share and bookmark if you like it.
As always I’m looking forward to your comments and… see you in Paris !

create a unique contact form with css3 transitions

Inspired by the contact form on Clear Span Media website I decided to recreate an effect of a letter sliding out from an envelope on mouse hover. You may see the demo here.
contact form preview

Download the source files

Contact form
.zip 330 kB

It works in browsers supporting css3 transitions. In IE the envelope is not visible, I certainly could have played a bit more with jQuery to reproduce a similar effect, but it’s not a part of this tutorial.
Let’s start with the html structure:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Contact Form</title>
</head>
<body>
	<div id="wrap">
		<h1>Send a message</h1>
		<div id='form_wrap'>
			<form>
				<p>Hello Joe,</p>
				<label for="email">Your Message : </label>
				<textarea  name="message" value="Your Message" id="message" ></textarea>
				<p>Best,</p>	
				<label for="name">Name: </label>
				<input type="text" name="name" value="" id="name" />
				<label for="email">Email: </label>
				<input type="text" name="email" value="" id="email" />
				<input type="submit" name ="submit" value="Now, I send, thanks!" />
			</form>
		</div>
	</div>
</body>
</html>

The idea is as follows (I tried to illustrate it in the scheme below): the #form_wrap is positioned relatively (top:0), with the envelope fixed to its bottom. The form is positioned relatively, with top:200px. The overlay is set to hidden for both form and #form_wrap. When mouse enters the #form_wrap its height and the height of form increase both of 350px, at the same time the top property of the #form_wrap changes to top:-200px.
contact scheme
We will need an envelope cut into two parts, the top part, visible over the letter (after.png) and the bottom part (before.png) partially covered by the letter. You’re welcome to use the .ai file available here.
envelopes Let’s start to complete the stylesheet:
contact schemeNext, we’ll add some styling to the form elements:

label {
			margin: 11px 20px 0 0; 
 			font-size: 16px; color: #b3aba1;
			text-transform: uppercase; 
			text-shadow: 0px 1px 0px #fff;
		}
	
input[type=text], textarea {
		font: 14px normal normal uppercase helvetica, arial, sans-serif;
		color: #7c7873;background:none;
		width: 380px; height: 36px; padding: 0px 10px; margin: 0 0 10px 0;
		border:1px solid #f8f5f1;
		-moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px;
		-moz-box-shadow: inset 0px 0px 1px #726959;
                -webkit-box-shadow:  inset 0px 0px 1px #b3a895; 
                box-shadow:  inset 0px 0px 1px #b3a895;
		}	
	
textarea { height: 80px; padding-top:14px;}
		
textarea:focus, input[type=text]:focus {background:rgba(255,255,255,.35);}
		
#form_wrap input[type=submit] {
		position:relative;font-family: 'YanoneKaffeesatzRegular'; 
		font-size:24px; color: #7c7873;text-shadow:0 1px 0 #fff;
		width:100%; text-align:center; opacity:0;
		background:none;
		cursor: pointer;
		-moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; 
		}
		
#form_wrap:hover input[type=submit] {z-index:1;opacity:1;}
		
#form_wrap:hover input:hover[type=submit] {color:#435c70;}

So far we haven’t used the transition, click here to see where we are.

We will add the same transition to form and #form_wrap. The four parameters correspond to the transition property, duration, timing function and its delay.

  -webkit-transition: all 1s ease-in-out .3s;
  -moz-transition: all 1s ease-in-out .3s;
  -o-transition: all 1s ease-in-out .3s;
  transition: all 1s ease-in-out .3s;

Then we’ll add another transition to the input[type=submit] element. The first set of settings corresponds to the behavior when mouse leaves the #form_wrap, the second when it hovers the #form_wrap. I wanted to make sure that the submit element does not appear until the form and #form_wrap transition is finished. On the other hand it starts to disappear immediately when mouse leaves #form_wrap.


	#form_wrap input[type=submit] {
		-webkit-transition: opacity 0.6s ease-in-out 0s;
		-moz-transition: opacity .6s ease-in-out 0s;
		-o-transition: opacity .6s ease-in-out 0s;
		transition: opacity .6s ease-in-out 0s; 
		}
		
	#form_wrap:hover input[type=submit] {
		-webkit-transition: opacity .5s ease-in-out 1.3s;
		-moz-transition: opacity .5s ease-in-out 1.3s;
		-o-transition: opacity .5s ease-in-out 1.3s;
                transition: opacity .5s ease-in-out 1.3s;
		}
		

It’s almost ready, I will just add some jQuery so as it works in IE. The transition is similar, but not exactly the same:

<!--[if IE]><script>
	$(document).ready(function() { 
            $("#form_wrap").addClass('hide');
            $("#form_wrap").prepend( '<div id="before"></div>').append( '<div id="after"</div>');
            $("#form_wrap").hover(function(){
	         $(this).stop(true, false).animate({
	              height : '836px',
	              top : '-200px'
	         }, 2000); 	
            $('form').stop(true, false).animate({
		height : '580px'
		}, 2000, function(){
                         $('#form_wrap input[type=submit]').css({'z-index' : '1', 'opacity' : '1'})} ) }, function() {
		$('#form_wrap input[type=submit]').stop(true, true).css({ 'opacity' : '0'})
	        $(this).stop(true, false).animate({
			height : '446px',
			top : '0px'

		}, 2000); 	
		$('form').stop(true, false).animate({
				height : '200px'}, 2000)	
		})
})
</script><![endif]-->

You just need to add in the stylesheet #form_wrap.hide:after, #form_wrap.hide:before {display:none;} and

#before {position:absolute;
		  bottom:128px;left:0px;
		  background:url('images/before.png');
		  width:530px;height: 316px;}
	
#after {position:absolute;
		bottom:0px;left:0;
		background:url('images/after.png');
		width:530px;height: 260px; }

Looking forward to your comments, if you find this tutorial useful, please share and bookmark.