Miguel Rodríguez does effective software development.

Buttons and menus with animation only with CSS3

Be aware that Modernizr is being used in this tutorial, additionally, the behavior of the menu and its buttons may not be displayed the same way for every browser.
Requirements:
 
  • You should know some HTML basics 
  • You should know some CSS basics 
  • Because I am using Modernizr, you should know some basics of it, for more information visit Modernizr website or read this article.
What you'll learn:
 
  • Using CSS3 animations
  • Using CSS3 transitions
  • Giving a good look to objects with shadows
In this tutorial we are going to see how powerful is CSS3, we are going to create a menu up to three levels with effects only with CSS3 and nothing more, no JavaScript, no flash, nothing more but HTML and CSS, the tutorial is divided in two parts, the creation of the buttons where the look and other things strictly related to the buttons will be seen, and the creation of the menu where the structure and behavior of the menu will be considered, the code bellow is the whole CSS code that we are going to analyze, the code of the menu will be considered in the 'creation of the menu' section.
  1. /*begin buttons style*/
  2. ul.menu a{
  3. display:block;
  4. text-decoration:none;
  5. }
  6.  
  7. input[type=submit], button, ul.menu a{
  8. width:8em;
  9. text-align:center;
  10. height:1.8em;
  11. line-height:1.8em;
  12. background-color:blue;
  13. font-size:1em;
  14. color:black;
  15. }
  16.  
  17. .borderradius input[type=submit], .borderradius button, .borderradius ul.menu a{
  18. border-radius:3px !important;
  19. }
  20.  
  21. .boxshadow input[type=submit], .boxshadow button, .boxshadow ul.menu a{
  22. box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  23. -o-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  24. -ms-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  25. -moz-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  26. -webkit-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  27. }
  28.  
  29. .no-boxshadow input[type=submit], .no-boxshadow button, .no-boxshadow ul.menu a{
  30. border-top: solid 1px #8888FA;
  31. border-left: solid 1px #0000A1;
  32. border-right: solid 1px #8888FA;
  33. border-bottom: solid 1px #0000A1;
  34. }
  35.  
  36. .boxshadow input[type=submit]:active, .boxshadow button:active, .boxshadow ul.menu a:active{
  37. line-height:2em;
  38. box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  39. -o-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  40. -ms-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  41. -moz-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  42. -webkit-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  43. }
  44.  
  45. .no-boxshadow input[type=submit]:active, .no-boxshadow button:active, .no-boxshadow ul.menu a:active{
  46. border-top: solid 1px #0000A1;
  47. border-left: solid 1px #8888FA;
  48. border-right: solid 1px #0000A1;
  49. border-bottom: solid 1px #8888FA;
  50. }
  51.  
  52. input[type=submit]:hover, button:hover, ul.menu a:hover{
  53. color:#C55353;
  54. }
  55.  
  56. .boxshadow input[type=submit], .boxshadow button{
  57. border:0;
  58. }/*end buttons style*/
  59.  
  60. /*begin button transition*/
  61. .csstransitions.boxshadow input[type=submit], .csstransitions.boxshadow button, .csstransitions.boxshadow ul.menu a{
  62. transition: color 0.5s, line-height 0.3s, box-shadow 0.3s;
  63. -moz-transition: color 0.5s, line-height 0.3s, box-shadow 0.3s, -moz-box-shadow 0.3s;
  64. -webkit-transition: color 0.5s, line-height 0.3s, box-shadow 0.3s, -webkit-box-shadow 0.3s;
  65. -o-transition: color 0.5s, line-height 0.3s, box-shadow 0.3s, -o-box-shadow 0.3s;
  66. }/*end button transition*/
  67.  
  68. /*begin menus*/
  69. ul.menu, ul.menu li{
  70. display:block;
  71. position:relative;
  72. padding:0 !important;
  73. margin-bottom:0 !important;
  74. margin-left:0 !important;
  75. list-style:none !important;
  76. list-style-type:none !important;
  77. list-style-image:none !important;
  78. list-style-position:outside !important;
  79. float:none;
  80. }/*end menus: all menus are defined here*/
  81.  
  82. /*begin menu options*/
  83. ul.menu li{
  84. margin-right:2em;
  85. float:left;
  86. }
  87. ul.menu li.last{
  88. margin-right:0px;
  89. }/*end menu options*/
  90.  
  91. /*begin all submenus*/
  92. ul.menu ul{
  93. padding:0;
  94. display:none;
  95. }/*end all submenus*/
  96.  
  97. /*begin 2 level submenu*/
  98. ul.menu li:hover ul, ul.menu li ul li:hover ul{
  99. display:block;
  100. animation:fade 3s;
  101. -webkit-animation:fade 3s;
  102. -moz-animation:fade 3s;
  103. -o-animation:fade 3s;
  104. -ms-animation:fade 3s;
  105. animation-play-state:running;
  106. -moz-animation-play-state:running;
  107. -webkit-animation-play-state:running;
  108. -o-animation-play-state:running;
  109. -ms-animation-play-state:running;
  110. }
  111.  
  112. ul.menu ul{
  113. position:absolute;
  114. top:1.8em;
  115. }
  116.  
  117. ul.menu li ul li{
  118. clear:both;
  119. }/*end 2 level submenu: the submenu has an excessive width and height to prevent clipping*/
  120.  
  121. /*begin 3 level horizontal submenu*/
  122. ul.menu li:hover ul ul{
  123. display:none;
  124. }
  125.  
  126. ul.menu li ul li:hover ul{
  127. display:block;
  128. }
  129.  
  130. ul.menu ul ul{
  131. position:absolute;
  132. left:100%;
  133. top:0;
  134. }/*end 3 level horizontal submenu*/
  135.  
  136. /*begin main menu animation*/
  137. @keyframes fade
  138. {
  139. 0% {opacity:0;}
  140. 100% {opacity:1;}
  141. }
  142.  
  143. @-o-keyframes fade
  144. {
  145. 0% {opacity:0;}
  146. 100% {opacity:1;}
  147. }
  148.  
  149. @-ms-keyframes fade
  150. {
  151. 0% {opacity:0;}
  152. 100% {opacity:1;}
  153. }
  154.  
  155. @-moz-keyframes fade
  156. {
  157. 0% {opacity:0;}
  158. 100% {opacity:1;}
  159. }
  160.  
  161. @-webkit-keyframes fade
  162. {
  163. 0% {opacity:0;}
  164. 100% {opacity:1;}
  165. }/*end main menu animation*/
 

Creating the buttons

 
First, we have to set a style for all the buttons of each menu, technically, this buttons style is applied to the link elements in the menus, additionally, we are going to set the same style to all the button elements and the buttons in all the forms, all the buttons will have a fixed width and height, keep in mind that the text for each button should not be too long, all the buttons have a specific behavior in case the user hover or click the button, we can also set a transition so the properties will change smoothly, we are going to review the code step by step.
 
  1. /*begin buttons style*/
  2. ul.menu a{
  3. display:block;
  4. text-decoration:none;
  5. }
  6.  
  7. input[type=submit], button, ul.menu a{
  8. width:8em;
  9. text-align:center;
  10. height:1.8em;
  11. line-height:1.8em;
  12. background-color:blue;
  13. font-size:1em;
  14. color:black;
  15. }
  16.  
  17. .borderradius input[type=submit], .borderradius button, .borderradius ul.menu a{
  18. border-radius:3px !important;
  19. }
CSS3 Buttons
The measures of the buttons are fixed.
Attribution: 
This is the first part of the definition of the buttons, the button must have fixed measures, so the 'width' property of all the buttons was set to 8em, and the 'height' and 'line-height' properties were set to 1.8em, the 'line-height' property was defined in order to animate the text inside the button, the 'height' property will prevent the 'line-height' property to affect the shape of the buttons, the background color and the text color are set here, the sample color that is being used for the background is blue, although the text color was set to 'black', when the user hover the button the text color will change to another color, the text inside the buttons will be centered, if the text is to long for the button, the 'width' property can be changed, other properties were defined to improve the look of the button such as 'border-radius'.
  1. .boxshadow input[type=submit], .boxshadow button, .boxshadow ul.menu a{
  2. box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  3. -o-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  4. -ms-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  5. -moz-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  6. -webkit-box-shadow: -1px 1px 6px rgba(0,0,0,0.5), 2px -2px 2px 0px rgba(0,0,0,0.5) inset, -2px 2px 2px 0px rgba(255,255,255,0.5) inset;
  7. }
  8.  
  9. .no-boxshadow input[type=submit], .no-boxshadow button, .no-boxshadow ul.menu a{
  10. border-top: solid 1px #8888FA;
  11. border-left: solid 1px #0000A1;
  12. border-right: solid 1px #8888FA;
  13. border-bottom: solid 1px #0000A1;
  14. }
Button shadows (Workaround, CSS3)
If box-shadow is not available use borders with similar colors instead of shadows.
Attribution: 
In order to improve the look of the buttons, two transparent inner shadows will be used, a light upper shadow and a dark lower shadow, those shadows will improve drastically the look of the buttons adding a convex effect, if the box-shadow feature is not available, a fallback must be set, replacing those shadows with two borders with similar colors is a good idea, make sure those colors are similar to the color of the shadows mixed with background color of the button.
  1. .boxshadow input[type=submit]:active, .boxshadow button:active, .boxshadow ul.menu a:active{
  2. line-height:2em;
  3. box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  4. -o-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  5. -ms-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  6. -moz-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  7. -webkit-box-shadow: 0px 0px 0px rgba(0,0,0,0.6), -2px 2px 2px 0px rgba(0,0,0,0.5) inset, 2px -2px 2px 0px rgba(255,255,255,0.5) inset;
  8. }
  9.  
  10. .no-boxshadow input[type=submit]:active, .no-boxshadow button:active, .no-boxshadow ul.menu a:active{
  11. border-top: solid 1px #0000A1;
  12. border-left: solid 1px #8888FA;
  13. border-right: solid 1px #0000A1;
  14. border-bottom: solid 1px #8888FA;
  15. }
  16.  
  17. input[type=submit]:hover, button:hover, ul.menu a:hover{
  18. color:#C55353;
  19. }
Active button (Shadows, CSS3)
Attribution: 
This is where the behavior of the buttons is defined, the text color of the buttons will change on hover as well as its inner shadow and the 'line-height' property will change on click, by the time the user clicks, the inner shadows will change to the opposite making the buttons look concave, the outer shadow will disappear intensifying the sensation that the button was pressed, the 'line-height' property will increase in order to make the text look lower than usual, the 'height' property of the buttons was previously set, therefore, modifying the 'line-height' property will not affect the shape of the buttons, unfortunately, changing the 'line-height' property of the button elements on Firefox may have no effect.
  1. .boxshadow input[type=submit], .boxshadow button{
  2. border:0;
  3. }/*end buttons style*/
The borders of the button elements are overriden in order to give all the buttons the same look.
  1. /*begin button transition*/
  2. .csstransitions.boxshadow input[type=submit], .csstransitions.boxshadow button, .csstransitions.boxshadow ul.menu a{
  3. transition: color 0.5s, line-height 0.3s, box-shadow 0.3s;
  4. -moz-transition: color 0.5s, line-height 0.3s, box-shadow 0.3s, -moz-box-shadow 0.3s;
  5. -webkit-transition: color 0.5s, line-height 0.3s, box-shadow 0.3s, -webkit-box-shadow 0.3s;
  6. -o-transition: color 0.5s, line-height 0.3s, box-shadow 0.3s, -o-box-shadow 0.3s;
  7. }/*end button transition*/
This is optional, we can define a transition for all the changing properties, so all the shadows, the text color and the 'line-height' property will change gradually, the shadow is being defined in the transition twice to support browsers that only support 'box-shadow' with prefixes.
 

Creating the menus

 
Once the buttons are completed, we can make the menus, a menu is a list with a link in each of its items, in order to set a submenu you must put a list next to the link in the given item of the menu, this structure is needed in order to make the menu work, this tutorial was intended to make a menu only up to three level, this is how the menu structure should look like.
  1. <ul class="menu">
  2. <li>
  3. <a href="/yourURL" title="Parent menu option 1">Parent menu option 1</a>
  4. </li>
  5. <li>
  6. <a href="/yourURL" title="Parent menu option 2">Parent menu option 2</a>
  7. <ul>
  8. <li>
  9. <a href="/yourURL" title="Second level submenu option 1">Second level submenu option 1</a>
  10. </li>
  11. <li>
  12. <a href="/yourURL" title="Second level submenu option 2">Second level submenu option 2</a>
  13. <ul>
  14. <li>
  15. <a href="/yourURL" title="Third level submenu option 1">Third level submenu option 1</a>
  16. </li>
  17. <li>
  18. <a href="/yourURL" title="Third level submenu option 2">Third level submenu option 2</a>
  19. </li>
  20.  
  21. ...
  22.  
  23. <li>
  24. <a href="/yourURL" title="Third level submenu option N">Third level submenu option N</a>
  25. </li>
  26. </ul>
  27. </li>
  28.  
  29. ...
  30.  
  31. <li>
  32. <a href="/yourURL" title="Second level submenu option N">Second level submenu option N</a>
  33. </li>
  34. </ul>
  35. </li>
  36.  
  37. ...
  38.  
  39. <li>
  40. <a href="/yourURL" title="Parent menu option N">Parent menu option N</a>
  41. </li>
  42. </ul>
As you can see, each final option should have a class attribute called "last", if it is not possible for you, you can leave to set the attribute if you replace the selector '.last' with the pseudo-element selector ':last-child', be aware that that pseudo-element selector only works on CSS3, once the menu structure is done, the behavior of the menus must be defined, remember that the buttons are defined already, so the code bellow is just to define the behavior of the menus and its options.
  1. /*begin menus*/
  2. ul.menu, ul.menu li{
  3. display:block;
  4. position:relative;
  5. padding:0 !important;
  6. margin-bottom:0 !important;
  7. margin-left:0 !important;
  8. list-style:none !important;
  9. list-style-type:none !important;
  10. list-style-image:none !important;
  11. list-style-position:outside !important;
  12. float:none;
  13. }/*end menus: all menus are defined here*/
This is the code that will define all the menus and its options, part of these properties will affect the submenus as well, all the properties that could affect the look of the menus were overridden, the 'position' property of each menu option was set to 'relative', a menu option may have a button (a link element) and, possibly, a menu (a submenu we would say), the 'position' property of all the submenus is set to 'absolute', therefore, the submenu will be enclosed in the menu option helping the positioning of the submenu.
  1. /*begin menu options*/
  2. ul.menu li{
  3. margin-right:2em;
  4. float:left;
  5. }
  6. ul.menu li.last{
  7. margin-right:0px;
  8. }/*end menu options*/
The 'left' and 'margin-right' properties were set to place each menu option right after another with a margin at the right of each option excepting for the last one, however, the submenu options can not have these properties and they must be replaced or disabled.
  1. /*begin all submenus*/
  2. ul.menu ul{
  3. display:none;
  4. }/*end all submenus*/
This is a definition for all the submenus, it is just hiding all the submenus by default.
  1. /*begin 2 level submenu*/
  2. ul.menu li:hover ul, ul.menu li ul li:hover ul{
  3. display:block;
  4. animation:fade 3s;
  5. -webkit-animation:fade 3s;
  6. -moz-animation:fade 3s;
  7. -o-animation:fade 3s;
  8. animation-play-state:running;
  9. -moz-animation-play-state:running;
  10. -webkit-animation-play-state:running;
  11. -o-animation-play-state:running;
  12. }
  13.  
  14. ul.menu ul{
  15. position:absolute;
  16. top:1.8em;
  17. }
  18.  
  19. ul.menu li ul li{
  20. clear:both;
  21. }/*end 2 level submenu*/
Second level submenu positioning (CSS3)
Attribution: 
The second level submenus are defined here, the third level submenus will inherit part of these properties, this is where we set the animation to the submenus each time the user hover the option of the parent menu, the 'animation' property has a time of 3 seconds, this value can be changed as desired, at present all the browsers require a prefix to parse the 'animation' property, the 'animation-play-state' property was set in order to make sure it plays the animation each time the user hover the menu option, the second level submenus will be placed at the bottom of the parent menu, therefore, the 'top' property is set to 1.8em, the same value of the height of each button, the 'position' property was set to 'absolute' in order to place the submenus properly, remember that the submenu is in the menu option so the submenu will be positioned with regard to the menu option position, each submenu option has a 'clear' property to disable the effect of the 'left' property inherited from the parent menu options.
  1. /*begin 3 level submenu*/
  2. ul.menu li:hover ul ul{
  3. display:none;
  4. }
  5.  
  6. ul.menu li ul li:hover ul{
  7. display:block;
  8. }
  9.  
  10. ul.menu ul ul{
  11. position:absolute;
  12. left:100%;
  13. top:0;
  14. }/*end 3 level submenu*/
Third level submenu positioning
Attribution: 
The third level submenus must not appear if the second level submenu does, so it is necessary to make sure it will not appear in that situation by setting the 'display' property with the proper selectors, the third level submenu will be placed depending on the position of the second level submenu option, it is necessary to override the inherited position by setting the 'top' property to 0, the third level submenus must be placed to the right of the menu option, so the 'left' property of the submenu is set to 100%.
  1. /*begin main menu animation*/
  2. @keyframes fade
  3. {
  4. 0% {opacity:0;}
  5. 100% {opacity:1;}
  6. }
  7.  
  8. @-o-keyframes fade
  9. {
  10. 0% {opacity:0;}
  11. 100% {opacity:1;}
  12. }
  13.  
  14. @-moz-keyframes fade
  15. {
  16. 0% {opacity:0;}
  17. 100% {opacity:1;}
  18. }
  19.  
  20. @-webkit-keyframes fade
  21. {
  22. 0% {opacity:0;}
  23. 100% {opacity:1;}
  24. }/*end main menu animation*/
Lastly, this is the definition of the animation itself, it is just a simple fade effect making appear an object, in case that you want to modify the animation, remember that only the submenus have the animation not its options.
Once you apply all the code above the result would be a great menu with a fade effect, remember that this was made with CSS3 so unsupported browsers would only display the menu, not the effects, you can customize the animation to display the menu another way else, and please, if you apply this tutorial remember testing.

About me

About the author
Miguel Rodríguez is a freelance developer from Caracas - Venezuela. He is a persistent and goal-oriented person who tries to make the best use of the resources. He is positive, proactive and motivated enough to set a goal with the intention to fulfill it. Find more about him .