How to Create a CSS3 Wheel Menu

Final Product What You’ll Be Creating

There’s no better way to learn CSS3 than to get your hands dirty on an actual project and that’s exactly what we’re going to do. I’m going to teach you how to create an awesome, layered CSS3 wheel menu using a few beginner to advanced CSS techniques. So break out your favorite text editor or IDE and let’s get started on some CSS3 magic!
Today you’ll be learning how to create the candy cane teardrop out of the many different styles and color variations available. You will receive all variations in the source files. Also as an added bonus I’ve added a little bit of optional Javascript so that you can rotate your images depending on the hovered menu item. The source file even comes with its own documentation!
Note: Support for IE is limited at the moment. We’ll mostly be going through this for the purpose of pushing the envelope with what we can do in CSS3… but as with all things on the edge of practicality, it means sacrificing a bit of stability. We will address the IE topic at the end of the tutorial though!

The Video Tutorial

We’re offering this tutorial in two different formats today: A video as well as a full written tutorial below. Follow along with whichever method of learning you prefer (or both!) and we’ll get you to the end in no time!

The Written Tutorial

The step by step written tutorial is below. Be sure to grab the full downloadable source as well!

Step 1: The Layers

The first thing we want to do is create some layers that will overlap each other and stay in place while using as little code as possible. It’s important not to fill your code with a lot of bloat and not to create a lot of
unnecessary floats or absolute positioned elements, so we’ll try to stay relative as much as possible.

The Code:









As you can see the code is pretty straight-forward. We have essentially stacked one layer on top of another and this way they’ll be able to hold their positions.

Next we want to add an image to the center of the wheel, or teardrop in this case. To do that we’ll simply add the following code in-between the wrap4 class and the completer class. This will lock the image to the center of the canvas. We’ll just use a Rockable image for this one because they’re awesome!
  1. class=“img1”>class=“orbit orbit-frame” src=“images/card18.jpg” alt=“card08”>  
Now we’ll want to add some styling to each layer one by one.

#menu-wrap:

This will be the main container for your wheel menu. It also contains any universal fonts and font sizes effecting anything that’s inside of the div id=”menu-wrap”.
  1. #menu-wrap{  
  2.     background:#e7e7e7; /* This isn’t needed */  
  3.     height:600px; /* This is important and keeps the wheel in place when hovering over elements */  
  4.     font-family:sans-serif, Franklin Gothic Medium,Helvetica, Arial; /* If not using Franklin, it will automatically go to the next font in the family */  
  5.     font-size:14px; /* Establishes the global font size */  
  6.     letter-spacing: 1px !important; /* Effects spacing between letters for all fonts in the wheel */  
  7.     }  
We’ll go ahead and make sure that our center image is styled correctly by placing it in the center of the wheel using margins, adding some dimensions to it and a border.
  1. #menu-wrap .orbit{  
  2.     height: 210px;  
  3.     margin: 32px; /* Pushes the images in the display to the center */  
  4.     position: absolute;  
  5.     width: 210px;  
  6.     }  
  7.  
  8. #menu-wrap .orbit-frame{  
  9.     border:2px solid #999; /* Creates a division between the image and wrap5 */  
  10.     }  
All wrappers: We’ll want to create some styles that apply to all main wrappers by adding a universal border radius, putting them all in the center, adding a relative position so that everything stays contained and pushing them down to to get the even layered effect.
  1. .wrap1, .wrap2, .wrap3, .wrap4, .wrap5, .nav-holder{  /* styles all of the wheel containers */  
  2.     -moz-border-radius: 220px 0 200px 220px;  /* firefox */  
  3.     -webkit-border-radius: 220px 0 200px 220px; /* webkit */  
  4.     border-radius: 220px 0 200px 220px;   /* opera */  
  5.     margin:0 auto; /* centers all the wrappers relative to each other */  
  6.     position:relative !important;  /* Do not touch unless you know what you are doing */  
  7.     top:20px;  
  8.     }  

.wrap1:

This is your biggest layer that sits behind all the others. We’re going to create a gradient red background and use a solid red fallback for older browers. We’ll also be using CSSpie to tell IE that it’s ok to use these styles. After that all we need to do is add a width and height and you’re done. You want to make sure the width and height are larger than all the other layers so that it shows behind them.
  1. .wrap1{  
  2.     background: #FF0000; /* old browsers */  
  3.     background: -moz-linear-gradient(top, #FF0000 0%, #990000 100%); /* firefox */  
  4.     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FF0000), color-stop(100%,#990000)); /* webkit */  
  5.     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr=‘#FF0000’, endColorstr=‘#990000’,GradientType=0 ); /* ie */  
  6.     background: linear-gradient(top, #FF0000 0%, #990000 100%); /*future CSS3 browsers*/  
  7.     -pie-background: linear-gradient(top, #FF0000 0%, #990000 100%); /*IE fix using Pie*/  
  8.     height:394px;  
  9.     width:394px;  
  10.     }  

.wrap2:

Now for wrap 2 we’re going to do the exact same thing only we’ll use variations of white as the gradient, and add an outer and inner box shadow to create a slight bevel effect plus the backdrop shadow. Then we need to make the width and height about 40px smaller than the main layer to make it nice and even.
  1. .wrap2{  
  2.     background: #FFFFFF; /* old browsers */  
  3.     background: -moz-linear-gradient(top, #FFFFFF 0%, #DCBE8F 100%); /* firefox */  
  4.     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(100%,#DCBE8F)); /* webkit */  
  5.     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr=‘#FFFFFF’, endColorstr=‘#DCBE8F’,GradientType=0 ); /* ie */  
  6.     background: linear-gradient(top, #FFFFFF 0%, #DCBE8F 100%); /*future CSS3 browsers*/  
  7.     -pie-background: linear-gradient(top, #FFFFFF 0%, #DCBE8F 100%); /*IE fix using Pie*/  
  8.     height:354px;  
  9.     width:354px;  
  10.     -moz-box-shadow: 15px 31px 19px 8px rgba(0, 0, 0, 0.6), 0 -30px 46px -1px rgba(0, 0, 0, 0.65) inset;  
  11.     -webkit-box-shadow: 15px 31px 19px 8px rgba(0, 0, 0, 0.6), 0 -30px 46px -1px rgba(0, 0, 0, 0.65) inset;  
  12.     box-shadow: 15px 31px 19px 8px rgba(0, 0, 0, 0.6), 0 -30px 46px -1px rgba(0, 0, 0, 0.65) inset;  
  13.     }  

.wrap3 & 4:

We will now repeat the process for all the other wrappers using different colored gradients and making each layer 40px smaller than the last.
  1. .wrap3{  
  2.     background: #FF0000; /* old browsers */  
  3.     background: -moz-linear-gradient(top, #FF0000 0%, #990000 100%); /* firefox */  
  4.     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FF0000), color-stop(100%,#990000)); /* webkit */  
  5.     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr=‘#FF0000’, endColorstr=‘#990000’,GradientType=0 ); /* ie */  
  6.     background: linear-gradient(top, #FF0000 0%, #990000 100%); /*future CSS3 browsers*/  
  7.     -pie-background: linear-gradient(top, #FF0000 0%, #990000 100%); /*IE fix using Pie*/  
  8.     height:314px;  
  9.     width:314px;  
  10.     }  
  11.   
  12. .wrap4{  
  13.     border: 2px solid #FF0000;  
  14.     background: #990000; /* old browsers */  
  15.     background: -moz-linear-gradient(top, #990000 0%, #CC0000 55%, #FF0000 57%); /* firefox */  
  16.     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#990000), color-stop(55%,#CC0000), color-stop(57%,#FF0000)); /* webkit */  
  17.     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr=‘#990000’, endColorstr=‘#FF0000’,GradientType=0 ); /* ie */  
  18.     background: linear-gradient(top, #990000 0%, #CC0000 55%, #FF0000 57%); /*future CSS3 browsers*/  
  19.     -pie-background: linear-gradient(top, #990000 0%, #CC0000 55%, #FF0000 57%); /*IE fix using Pie*/  
  20.     -moz-box-shadow: 1px 1px 7px 2px rgba(0, 0, 0, 0.65), 1px 1px 0 2px rgba(125, 121, 32, 0.32) inset, 5px 5px 9px 6px rgba(221, 252, 116, 0.81) inset;  
  21.     -webkit-box-shadow: 1px 1px 7px 2px rgba(0, 0, 0, 0.65), 1px 1px 0 2px rgba(125, 121, 32, 0.32) inset, 5px 5px 9px 6px rgba(221, 252, 116, 0.81) inset;  
  22.     box-shadow: 1px 1px 7px 2px rgba(0, 0, 0, 0.65), 1px 1px 0 2px rgba(125, 121, 32, 0.32) inset, 5px 5px 9px 6px rgba(221, 252, 116, 0.81) inset;  
  23.     height:274px;  
  24.     width:274px;  
  25.     }  

.wrap5 & .nav-holder:

Now we can style wrap5 and the nav-holder which will hold all the menu items in place and for the candycane style, we’ll make it black to add a nice neutral contrast while wrap5 will be white and will serve as the container for the center image. What we’re doing here is cutting out the background so that you can see through wrap5 and the nav-holder, making the other layers appear behind it as well as the center image. After making it transparent we’ll add a black border to the nav-holder and a white border to wrap5. The nav-holder’s border should be hidden on the right side (for the sub-menus), doubled on the left side (for the main menus) and solid for the rest creating a nice and easy effect while minimizing the amount of layers we have to add. Traditionally with this effect you could add up to 5 or 6 new layers, this saves a lot of code.
This time the wrap5 width and height will be 60px less than the other layers to make it nice and even again. Another 10px push at the top will help align the layer and an inner box shadow will give us a nice perspective of distance between wrap5 and the center image.
Adding a top of 0 to the nav-holder will automatically align the layers with the others. We’ll also use a negative margin for further top-left alignment and create a proportional height/width to make it fit nicely on top of the other layers.
  1. .wrap5{  
  2.     -moz-box-shadow: 9px 9px 5px 0 rgba(0, 0, 0, 0.75) inset, 5px 5px 5px 0 rgba(0, 0, 0, 0.75);  
  3.     -webkit-box-shadow: 9px 9px 5px 0 rgba(0, 0, 0, 0.75) inset, 5px 5px 5px 0 rgba(0, 0, 0, 0.75);  
  4.     box-shadow: 9px 9px 5px 0 rgba(0, 0, 0, 0.75) inset, 5px 5px 5px 0 rgba(0, 0, 0, 0.75);  
  5.     border: 20px solid #FFF;  /* creates the wrap to see the image behind it */  
  6.     height: 214px;  
  7.     top: 10px;  /* center the element */  
  8.     width: 214px;  
  9.     }  
  10.   
  11. .nav-holder{  
  12.     background: none repeat scroll 0 0 transparent;  
  13.     border-color: #121212;  /***  The border declarations are used to create the final wrapper, middle see through and hides the right border to show the submenus */  
  14.     border-style: solid hidden solid double;  
  15.     border-width: 73px medium 73px 73px;  
  16.     height: 252px;  
  17.     margin: -92px;  /*  centers the object on relative elements */  
  18.     top: 0;  
  19.     width: 324px;  
  20.     }  
“The nav-holder’s border should be hidden on the right side (for the sub-menus), doubled on the left side (for the main menus) and solid for the rest creating a nice and easy effect while minimizing the amount of layers we have to add.”
Well that was easy enough. So after you’ve finish all of that, hopefully you’ve learned something new to add to your skill-set already. However, this is what you’re creation should look like so far. If it doesn’t look like this, please go through the code again and see if you may have missed something… don’t worry, it’s probably something very minor.
The Completers: Hmm… does this look incomplete to you? We need to top it off with a couple of layers I’ve called completers so that we can hide parts of the center image and bring the nav-holder further around the other layers creating a nice rounded effect and closing it off.
To do what I’ve just mentioned is fairly simple. We can make most of the styling apply to both completers for less code. Let’s add a border radius to one side to make a nice curve, then we’ll use transform to align the completer between wrap1 and wrap5. Adding our background color is very important or nothing will show up. We have to make this layer absolute positioned and move it around to the right and top to get it lined up perfectly.
.completer1 will have a display of none for this teardrop style. On other styles such as the wheel we’ve deleted that part to make so that it does display.
.completer2 has a little more rotation and we need to push it down a little to make it fit.
  1. .completer, .completer2{ /** absolute elements to hide the border of images **/  
  2.     -moz-border-radius: 0 120px 0 113px;  /* firefox */  
  3.     -webkit-border-radius: 0 120px 0 113px; /* webkit */  
  4.     border-radius: 0 120px 0 113px; /* opera */  
  5.     -moz-transform: rotate(-20deg); /* firefox */  
  6.     -webkit-transform: rotate(-21deg); /* webkit */  
  7.     -o-transform: rotate(-20deg); /* opera */  
  8.     -ms-transform: rotate(-20deg); /* ie9 and future versions */  
  9.     transform: rotate(-20deg); /* older browsers */  
  10.     background-color: #121212;  
  11.     background-image: none;  
  12.     background-position: 0 0;  
  13.     background-repeat: repeat;  
  14.     height: 135px;  
  15.     position: absolute;  
  16.     right: -24px;  
  17.     top: -56px;  
  18.     width: 130px;  
  19.     }  
  20.   
  21. .completer{  
  22.     display:none;  
  23.     }  
  24.   
  25. .completer2{  
  26.     -moz-transform: rotate(110deg); /* firefox */  
  27.     -webkit-transform: rotate(111deg); /* webkit */  
  28.     -o-transform: rotate(110deg); /* opera */  
  29.     -ms-transform: rotate(110deg); /* ie9 and future versions */  
  30.     transform: rotate(110deg); /* older browsers */  
  31.     top: 195px;  
  32.     }  
After you’ve added the completers then you should have something like this… Again if you don’t have the same thing as what you see here, just check over your code and see what you missed.

You may also like...