Pseudo elements with custom attributes to create a css3 menu that will bounce

You must have already seen this (what I call “bouncing”) hover effect in navigation menus. Curious how to recreate it easily ?
Below you’ll find my approach, for a simple 1-level menu as well as a drop-down one.
It’s pure css, I use an :after pseudo-element with a custom attribute.
Make sure you’re using a modern browser (support for css3 transitions is required) and click on the image below to see the demo.

Bouncing css3 menu using pseudo elements with custom attributes - demo

The mark-up is typical

<nav class="ph-lift">
	<li class="active"><a href="#home" data-title="Home">Home</a></li>
	<li><a href="#portfolio" data-title="My works">My works</a></li>
	<li><a href="#about" data-title="Who am I?">Who am I?</a></li>
	<li><a href="#contact" data-title="Contact me">Contact me</a></li>

Note that I added a data-title attribute containing the link label to each a.
The idea is to have a li element with overflow:hidden. The first on-hover effect is to change its background color and add some inner shadow with a smooth transition (don’t forget the vendor prefixes !). ul li {
    float: left;
    height: 90px;
    line-height: 90px;
    background: white;
    overflow: hidden;
    transition: all.6s ease; } ul li:hover {
      box-shadow: 0 0 15px rgba(0, 0, 0, 0.3) inset;
      background: teal; }

With :after pseudo element I generate a “copy” of the link element, that is positioned below the link. For its content I use the “data-title” attribute.
On mouse-hover the link changes its margin-top property (again, with a smooth transition). ul li a {
      display: block;
      text-decoration: none;
      color: #007e7e;
      padding: 0 45px;
      margin-top: 0;
      transition: all.6s ease; } ul li:hover a {
      margin-top: -90px;
      color: white;
      text-shadow: 0 1px 2px  black; } ul li a:after {
        content: attr(data-title);
        display: block; }

In the case of drop-down menu, we can no longer have the li {overflow:hidden}. In this case I change the mark-up:

<nav class="ph-lift1">
	<li class="active"><a href="#home" data-title="Home"><span data-title="Home">Home</span></a>
	<li><a href="#"><span data-title="Featured">Featured</span></a></li>
	<li><a href="#"><span data-title="Top 10">Top 10</span></a></li>
	<li><a href="#portfolio"><span data-title="My works">My works</span></a>
	<li><a href="#"><span data-title="Web design">Web design</span></a></li>
	<li><a href="#"><span data-title="Illustrations">Illustrations</span></a></li>
	<li><a href="#"><span data-title="Patterns">Patterns</span></a></li>
	<li><a href="#"><span data-title="Who am I?">Who am I?</span></a></li>
	<li><a href="#"><span data-title="Contact me">Contact me</span></a>
	<li><a href="#"><span data-title="Email me">Email me</span></a></li>
	<li><a href="#"><span data-title="Network">Network</span></a></li>

The main idea is still the same. Now, I apply overflow:hidden to the a element, and generate the pseudo element for my span. > ul > li {
    float: left; } ul li {
    height: 80px;
    line-height: 80px;
    background: white;
    -webkit-transition: all.6s ease;
    -moz-transition: all.6s ease;
    -o-transition: all.6s ease;
    -ms-transition: all.6s ease;
    transition: all.6s ease; } ul li ul {
      max-height: 0;
      -webkit-transition: all.6s ease;
      -moz-transition: all.6s ease;
      overflow: hidden;
      display: block; } ul li:hover {
      box-shadow: 0 0 15px rgba(0, 0, 0, 0.3) inset;
      background: darkolivegreen; } ul li:hover ul {
      max-height: 300px; } ul li a {
      display: block;
      overflow: hidden;
      text-decoration: none;
      color: #546a2f;
      height: 80px; } ul li ul li a {
      color: #7e7e00; } ul li ul li:hover {
      background: olive; } ul li a span {
        -webkit-transition: all.6s ease;
        -moz-transition: all.6s ease;
        -o-transition: all.6s ease;
        -ms-transition: all.6s ease;
        transition: all.6s ease;
        display: block;
        padding: 0 40px; } ul li:hover > a span {
      margin-top: -80px;
      color: white;
      text-shadow: 0 1px 2px  black; } ul li a span:after {
        content: attr(data-title);
        display: block; }

Don’t hesitate to play with this effect, it’s just a basic idea.
I hope you enjoyed this tutorial, if so – please share with the others. I’m looking forward to your feedback. Thanks.

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) 
	@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">
<link href='' rel='stylesheet' type='text/css'>
<link href='' 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">

		<h2>Sprites created with compass</h2>
		<a href="" type="submit" class="button" name="waiting">
		<a  href="#" class="button button-hover" title="hover">
		<a  href="#" class="button button-target" title="clicked">
		<ul class="social">
			<li><a class="icons-twitter" href="">Twitter</a></li>
			<li><a class="icons-dribbble" href="">Dribbble</a></li>
			<li><a class="icons-pinterest" href="">Pinterest</a></li>
			<li><a class="icons-deviantart" href="">DA</a></li>
			<li><a class="icons-flickr" href="">Flickr</a></li>
		<p>Buttons by <a title="created in Vains Faktory by Joe Vains" href="" target="_blank">Joe Vains</a></p>

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;
    @media only screen and (-webkit-min-device-pixel-ratio : 1.5), only screen and (min-device-pixel-ratio : 1.5) {
    @each $_icon in  twitter, dribbble, pinterest, deviantart, flickr {
	&.icons-#{$_icon} {
	  @include ph-sprites($icons,$icons2x, #{$_icon}, false, 7px, 7px);

Shopping in Paris – free vector

Still in the “shopping” theme (see my previous post) this time I prepared a simply illustration: a beautiful girl doing her shopping with Paris roofs and Eiffel Tower in the background. Created in Adobe Illustrator CS5 back saved to CS4 version.
What do you think ? – it’s my first time with human body (I mean in vector ;)) so I’d really appreciate your feedback.

It’s free for personal and commercial use. Enjoy your shopping.

Shopping in Paris

If you host this file please don’t forget to add a link to this site.
And if you like/use it please bookmark and share. Thank you.

Free vector shopping paper bag

Recently I needed a paper bag to illustrate a “shopping” theme. I decided to create one myself – and now I’m ready to share it with you, my visitors. It was created in Adobe Illustrator CS5 back saved to CS4 version.

It’s free for commercial use. Enjoy your shopping.

Shopping Paper Bag in vector format

If you host this file please don’t forget to add a link to this site.
And if you like/use it please bookmark and share. Thank you.

Free Vector chef – illustrate your cuisine

A simple vector illustration of a restaurant chef handling a pancake pan. With a slight retro flavor.
Enjoy – it’s free for personal and commercial use.

Vector chef with a pancake pan

If you host this file please don’t forget to add a link to this site.
And if you like/use it please bookmark and share. Thank you.

Vintage free vector TV-set

Vintage free vector TV

This time I share with you a retro TV set in vector format. It’s been created in Adobe Illustrator CS5 and back saved to CS4+.
You may use it for your personal and commercial projects. Feel free. However if you host this file please don’t forget to add a link to this site.

You’ll see a live example of how this vector was used in my experimental virtual card.

If you like/use it please bookmark and share. Thank you.

Download the source files

Vintage vector TV, CS4+ ai.
.zip 5MB

Create your portfolio gallery using html5 canvas – tutorial

In this tutorial we will build a photo gallery and enhance it with html5 canvas and css3 transitions. See the demo and try the hover effect. The grayscale “copies” of the images are created with canvas and we use pure css3 for the smooth changes.

Photo gallery with html5 canvas

Download the source files

Portfolio gallery with canvas
.zip 0.25MB

Step 1 : Html markup

Let’s start with a simple markup, each portfolio entry being an element of an unordered list.

<!DOCTYPE html>
	<meta charset="UTF-8" />
	<title>Gallery :: Tutorial by PeHaa </title>
	<script src=""></script>
	<div id="wrap">
		<ul id="gallery">
			<li><a href=""><img src="images/flo1.jpg"><div>Spring flowers 1</div></a></li>
			<li><a href=""><img src="images/lights2.jpg"><div>City lights 1</div></a></li>
			<li><a href=""><img src="images/flo3.jpg"><div>Spring flowers 2</div></a></li>
			<li><a href=""><img src="images/lights1.jpg"><div>City lights 2</div></a></li>
			<li><a href=""><img src="images/flo2.jpg"><div>Spring flowers 3</div></a></li>
			<li><a href=""><img src="images/lights3.jpg"><div>City lights 3</div></a></li>
		<p>Photos by <a href="">Pinkonhead</a></p>

Step 2: 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;}
:focus {outline: 0;}
a {text-decoration:none;}

We will use 300px x 300px images. The main containing element #wrap is centered up (margin: 0 auto) and given the width of 1020px (=340 x 3).
The list items are given float : left and are positioned relatively. The image title is wrapped in a div element that slides up on hover. To achieve a smooth effect we apply a css3 transition.
(Note that for the simplicity of this tutorial I don’t use any vendor prefixes. Therefore, you’ll find them in the source file to download).

#wrap {
  width: 1020px; 
  margin: 0 auto;
li {
  box-shadow:0 0 5px rgba(0,0,0,.35);
li div {
  padding: 0 10px;
  transition:height 1s;
li:hover div {

Click on the image to below to see the result at the current stage.

Photo gallery with canvas

Step 3: Canvas

Now, we will make use of the html5 canvas element to draw the grayscale versions of our images. Below you’ll find a createCanvas custom function that creates a canvas element, takes a copy of an image, performs the conversion and draws it to the canvas and finally inserts the canvas to the DOM where desired. With .each() method the createCanvas function is iterated across all images within the #gallery list.

$(window).load(function() {

	  $('#gallery img').each(function() {


	  function createCanvas(image) {

	    var canvas = document.createElement('canvas');
	    if (canvas.getContext) {
	      var ctx = canvas.getContext("2d");

// specify canvas size
	      canvas.width = image.width;
	      canvas.height = image.height;

// Once we have a reference to the source image object we can use 
// the drawImage(reference, x, y) method to render it to the canvas. 
//x, y are the coordinates on the target canvas where the image should be placed.
	      ctx.drawImage(image, 0, 0);

// Taking the image data and storing it in the imageData array. 
//You can read the pixel data on a canvas using the getImageData() method. 
// Image data includes the colour of the pixel (decimal, rgb values) and alpha value. 
// Each color component is represented by an integer between 0 and 255. 
// contains height x width x 4 bytes of data, with index values ranging from 0 to (height x width x 4)-1.
	      var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height),
	          pixelData =;

// Loop through all the pixels in the imageData array, and modify
// the red, green, and blue color values.
	      for (var y = 0; y < canvas.height; y++) {
	        for (var x = 0; x < canvas.width; x++) {

// You can access the color values of the (x,y) pixel as follows :
	          var i = (y * 4 * canvas.width) + (x * 4);

// Get the RGB values.
	          var red = pixelData[i];
	          var green = pixelData[i + 1];
	          var blue = pixelData[i + 2];

// Convert to grayscale. One of the formulas of conversion (e.g. you could try a simple average (red+green+blue)/3)   
	          var grayScale = (red * 0.3) + (green * 0.59) + (blue * .11);

	          pixelData[i] = grayScale;
	          pixelData[i + 1] = grayScale;
	          pixelData[i + 2] = grayScale;

// Putting the modified imageData back on the canvas.
	      ctx.putImageData(imageData, 0, 0, 0, 0, imageData.width, imageData.height);

// Inserting the canvas in the DOM, before the image:
	      image.parentNode.insertBefore(canvas, image);

Step 4: Styling the canvas

If you look into the generated code source you’ll find

<ul id="gallery">
	<li><a href=""><canvas width="300" height="300"></canvas><img src="images/flo1.jpg"><div>Spring flowers 1</div></a></li>
	<li><a href=""><canvas width="300" height="300"></canvas><img src="images/lights2.jpg"><div>City lights 1</div></a></li>

Let’s add some styling to define the canvas behavior in normal and hover state:

canvas {
  transition:opacity 1s .2s;
li:hover canvas {

And that’s it ! This example will not work in Internet Explorer versions below 9. You could provide an alternative solution using grayscale filter and adding some jQuery to recreate the transition effect on hover – but this part is not covered in this tutorial.

The beautiful photos featured here were taken by Pinkonhead, and are shared as freebies on her blog. Enjoy.