Making a CSS3 Animated Menu
Posted in #MenusMartin Angelov
In this short tutorial, we will be using the power of CSS3 effects and transitions, to build a JavaScript-free animated navigation menu which you can use to add a polished look to your website or template. We will be using some neat features such as the
:target pseudo selector and :after elements.The HTML
The first step is to define the HTML backbone of the website. We are using HTML5 tags extensively, so we will need to include the HTML5 enabling script for IE in the head section of the document. As it is enclosed in a conditional comment, it is only going to be requested in IE browsers and will not affect the performance of the others:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSS3 Animated Navigation Menu | Tutorialzine Demo</title>
<!-- Our CSS stylesheet file -->
<link rel="stylesheet" href="assets/css/styles.css" />
<!-- Including the Lobster font from Google's Font Directory -->
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Lobster" />
<!-- Enabling HTML5 support for Internet Explorer -->
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<header>
<h1>CSS3 Animated Navigation Menu</h1>
<h2>« Read and download on Tutorialzine</h2>
</header>
<nav>
<ul class="fancyNav">
<li id="home"><a href="#home" class="homeIcon">Home</a></li>
<li id="news"><a href="#news">News</a></li>
<li id="about"><a href="#about">About us</a></li>
<li id="services"><a href="#services">Services</a></li>
<li id="contact"><a href="#contact">Contact us</a></li>
</ul>
</nav>
<footer>Looks best in Firefox 4, usable everywhere.</footer>
</body>
</html>
You can notice that we are including a stylesheet from Google APIs. It contains a
@font-face declaration and includes the Lobster font into our page, from Google’s Web Font directory, which has grown to include more than 100 wonderful open source fonts, generously hosted by Google.
In the body of the document, we have the
header, nav and footer HTML5 tags, which divide the page into three sections with semantic value. We will be concentrating on the UL element inside the nav tag. This is our navigation menu.
The unordered list has a
fancyNav class applied to it, which we will be using to limit the effect of the CSS styles that we will be writing in a moment. This will make the code more portable and limit any possible side effects. Another thing to point out is that each of the LI elements has an unique ID, linked to from the anchor elements inside them. This will enable us to use the :target pseudo-class to style the currently selected menu item.
So lets move on to the CSS styles.
The CSS
You might find it surprising that the navigation menu we are building does not use any images (except for the home icon – a transparent png). Everything is done with CSS3 gradients, box shadows, and multiple backgrounds.
As for browser support, the menu works in the latest versions of Firefox, Chrome, Safari and Opera, while it is still usable in every IE version from 7 onwards. However, it does look best in Firefox 4, as it supports animating :before and :after pseudo elements via the transition property (other browsers are expected to follow suite).
Our CSS styles are defined in assets/styles.css. I would suggest that you download the menu code from the button above, and open that file in a text editor. We will be focusing primarily on the navigation menu, so I will be skipping the boring parts of the file.
Lets start styling the navigation menu! We first write the rules for the unordered list – targeted with the
fancyNav class, and the li items:.fancyNav{
/* Affects the UL element */
overflow: hidden;
display: inline-block;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
box-shadow: 0 0 4px rgba(255, 255, 255, 0.6);
-moz-box-shadow: 0 0 4px rgba(255, 255, 255, 0.6);
-webkit-box-shadow: 0 0 4px rgba(255, 255, 255, 0.6);
}
.fancyNav li{
/* Specifying a fallback color and we define CSS3 gradients for the major browsers: */
background-color: #f0f0f0;
background-image: -webkit-gradient(linear,left top, left bottom,from(#fefefe), color-stop(0.5,#f0f0f0), color-stop(0.51, #e6e6e6));
background-image: -moz-linear-gradient(#fefefe 0%, #f0f0f0 50%, #e6e6e6 51%);
background-image: -o-linear-gradient(#fefefe 0%, #f0f0f0 50%, #e6e6e6 51%);
background-image: -ms-linear-gradient(#fefefe 0%, #f0f0f0 50%, #e6e6e6 51%);
background-image: linear-gradient(#fefefe 0%, #f0f0f0 50%, #e6e6e6 51%);
border-right: 1px solid rgba(9, 9, 9, 0.125);
/* Adding a 1px inset highlight for a more polished efect: */
box-shadow: 1px -1px 0 rgba(255, 255, 255, 0.6) inset;
-moz-box-shadow: 1px -1px 0 rgba(255, 255, 255, 0.6) inset;
-webkit-box-shadow: 1px -1px 0 rgba(255, 255, 255, 0.6) inset;
position:relative;
float: left;
list-style: none;
}
Notice the huge list of CSS3 gradient syntaxes. All recent versions of Firefox, Chrome and Safari support gradients. With Opera and IE 10 (currently in platform preview mode), also joining in with their latest versions. Initially there were two competing syntaxes, backed by Mozilla (Firefox) on one side and Webkit (Chrome and Safari) on the other, but Firefox’s gradient syntax has been agreed on as the industry standard.
The next step is to use the
:after pseudo element to create the dark shadows, displayed when you hover over a menu item:.fancyNav li:after{
/* This creates a pseudo element inslide each LI */
content:'.';
text-indent:-9999px;
overflow:hidden;
position:absolute;
width:100%;
height:100%;
top:0;
left:0;
z-index:1;
opacity:0;
/* Gradients! */
background-image:-webkit-gradient(linear, left top, right top, from(rgba(168,168,168,0.5)),color-stop(0.5,rgba(168,168,168,0)), to(rgba(168,168,168,0.5)));
background-image:-moz-linear-gradient(left, rgba(168,168,168,0.5), rgba(168,168,168,0) 50%, rgba(168,168,168,0.5));
background-image:-o-linear-gradient(left, rgba(168,168,168,0.5), rgba(168,168,168,0) 50%, rgba(168,168,168,0.5));
background-image:-ms-linear-gradient(left, rgba(168,168,168,0.5), rgba(168,168,168,0) 50%, rgba(168,168,168,0.5));
background-image:linear-gradient(left, rgba(168,168,168,0.5), rgba(168,168,168,0) 50%, rgba(168,168,168,0.5));
/* Creating borders with box-shadow. Useful, as they don't affect the size of the element. */
box-shadow:-1px 0 0 #a3a3a3,-2px 0 0 #fff,1px 0 0 #a3a3a3,2px 0 0 #fff;
-moz-box-shadow:-1px 0 0 #a3a3a3,-2px 0 0 #fff,1px 0 0 #a3a3a3,2px 0 0 #fff;
-webkit-box-shadow:-1px 0 0 #a3a3a3,-2px 0 0 #fff,1px 0 0 #a3a3a3,2px 0 0 #fff;
/* This will create a smooth transition for the opacity property */
-moz-transition:0.25s all;
-webkit-transition:0.25s all;
-o-transition:0.25s all;
transition:0.25s all;
}
The
:after declaration creates a real styleable element. It has a smooth horizontal gradient that darkens the menu item when hovered upon. As it is invisible by default (opacity is set to 0), we are using CSS3 transitions to animate it between zero and full opacity, triggered on hover. Unfortunately only Firefox supports animating pseudo elements at this moment, but other browsers are expected to soon introduce this feature.
Next we will be using the
:first-child and :last-child pseudo selectors to target the first and last menu items./* Treating the first LI and li:after elements separately */
.fancyNav li:first-child{
border-radius: 4px 0 0 4px;
}
.fancyNav li:first-child:after,
.fancyNav li.selected:first-child:after{
box-shadow:1px 0 0 #a3a3a3,2px 0 0 #fff;
-moz-box-shadow:1px 0 0 #a3a3a3,2px 0 0 #fff;
-webkit-box-shadow:1px 0 0 #a3a3a3,2px 0 0 #fff;
border-radius:4px 0 0 4px;
}
.fancyNav li:last-child{
border-radius: 0 4px 4px 0;
}
/* Treating the last LI and li:after elements separately */
.fancyNav li:last-child:after,
.fancyNav li.selected:last-child:after{
box-shadow:-1px 0 0 #a3a3a3,-2px 0 0 #fff;
-moz-box-shadow:-1px 0 0 #a3a3a3,-2px 0 0 #fff;
-webkit-box-shadow:-1px 0 0 #a3a3a3,-2px 0 0 #fff;
border-radius:0 4px 4px 0;
}
.fancyNav li:hover:after,
.fancyNav li.selected:after,
.fancyNav li:target:after{
/* This property triggers the CSS3 transition */
opacity:1;
}
Applying different styles to the first and last items is necessary, as we don’t want to display ugly borders that span outside the menu. We also round the appropriate corners of these elements.
Note: You can add class=”selected” to a list item in order to make it selected/active by default. This is useful when building templates or generating the menu with a server-side language.
After this we need to apply a fix to the menu. It is to hide the currently selected element when we hover on the menu again:
.fancyNav:hover li.selected:after,
.fancyNav:hover li:target:after{
/* Hides the targeted li when we are hovering on the UL */
opacity:0;
}
.fancyNav li.selected:hover:after,
.fancyNav li:target:hover:after{
opacity:1 !important;
}
And lastly all that is left is to style the anchor elements that reside in the LIs.
/* Styling the anchor elements */
.fancyNav li a{
color: #5d5d5d;
display: inline-block;
font: 20px/1 Lobster,Arial,sans-serif;
padding: 12px 35px 14px;
position: relative;
text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.6);
z-index:2;
text-decoration:none !important;
white-space:nowrap;
}
.fancyNav a.homeIcon{
background:url('../img/home.png') no-repeat center center;
display: block;
overflow: hidden;
padding-left: 12px;
padding-right: 12px;
text-indent: -9999px;
width: 16px;
}
With this our animated CSS3 menu is complete!
To Wrap Up
Having your navigation menu built entirely with CSS gives you a great deal of control. You can customize every part of the design by swapping a color value or the font. The most of the bulk in the code came from having to supply a separate declaration for each browser, something that will soon be a thing of the past.
Did you like this tutorial? Be sure to share your thoughts in the comment section below.
#colorNav > ul{
width: 450px;
margin:0 auto;
}
This limits the width and margin declarations to only the first unordered list, which is a direct descendant of our #colorNav item. Keeping this in mind, let’s see what he actual menu items look like:
#colorNav > ul > li{ /* will style only the top level li */
list-style: none;
box-shadow: 0 0 10px rgba(100, 100, 100, 0.2) inset,1px 1px 1px #CCC;
display: inline-block;
line-height: 1;
margin: 1px;
border-radius: 3px;
position:relative;
}
We are setting a inline-block display value so that the list items are shown in one line, and we are assigning a relative position so that we can offset the dropdowns correctly. The anchor elements contain the actual icons as defined by Font Awesome.
#colorNav > ul > li > a{
color:inherit;
text-decoration:none !important;
font-size:24px;
padding: 25px;
}
Now we can move on with the drop downs. Here we will be defining a CSS3 transition animation. We will be setting a maximum-height of 0 px, which will hide the dropdown. On hover, we will animate the maximum height to a larger value, which will cause the list to be gradually revealed:
#colorNav li ul{
position:absolute;
list-style:none;
text-align:center;
width:180px;
left:50%;
margin-left:-90px;
top:70px;
font:bold 12px 'Open Sans Condensed', sans-serif;
/* This is important for the show/hide CSS animation */
max-height:0px;
overflow:hidden;
-webkit-transition:max-height 0.4s linear;
-moz-transition:max-height 0.4s linear;
transition:max-height 0.4s linear;
}
And this is the animation trigger:
#colorNav li:hover ul{
max-height:200px;
}
The 200px value is arbitrary and you will have to increase it if your drop down list contains a lot of values which do not fit. Unfortunately there is no css-only way to detect the height, so we have to hard code it.
The next step is to style the actual drop-down items:
#colorNav li ul li{
background-color:#313131;
}
#colorNav li ul li a{
padding:12px;
color:#fff !important;
text-decoration:none !important;
display:block;
}
#colorNav li ul li:nth-child(odd){ /* zebra stripes */
background-color:#363636;
}
#colorNav li ul li:hover{
background-color:#444;
}
#colorNav li ul li:first-child{
border-radius:3px 3px 0 0;
margin-top:25px;
position:relative;
}
#colorNav li ul li:first-child:before{ /* the pointer tip */
content:'';
position:absolute;
width:1px;
height:1px;
border:5px solid transparent;
border-bottom-color:#313131;
left:50%;
top:-10px;
margin-left:-5px;
}
#colorNav li ul li:last-child{
border-bottom-left-radius:3px;
border-bottom-right-radius:3px;
}
And of course, we are going nowhere without some fancy colors! Here are 5 versions:
#colorNav li.green{
/* This is the color of the menu item */
background-color:#00c08b;
/* This is the color of the icon */
color:#127a5d;
}
#colorNav li.red{ background-color:#ea5080;color:#aa2a52;}
#colorNav li.blue{ background-color:#53bfe2;color:#2884a2;}
#colorNav li.yellow{ background-color:#f8c54d;color:#ab8426;}
#colorNav li.purple{ background-color:#df6dc2;color:#9f3c85;}
One neat aspect of using icon fonts, is that you can change the color of the icon by simply declaring a color property. This means that all customizations you might want to make can be done with CSS alone.
Done!
Icon fonts are a great addition to one’s web development toolset. As they are regular fonts, you can use thefont-size, color and text-shadow properties to customize them. This example doesn’t use images nor JS, so it should be fairly easy to match it with your current design and use it within a few minutes.
http://tutorialzine.com/2012/10/css3-dropdown-menu/
Paginating content is a standard choice when dealing with large chunks of data. The implementation usually involves passing the page number to the back-end, where the appropriate data is fetched from the database and returned in some form. A cumbersome process, but it is a necessary evil. Or is it?
When dealing with small data sets, wouldn’t it be better to have the content readily available, but still neatly organized and easy to access?
Today we are making a jQuery plugin that will enable you to convert a regular unordered list of items into a SEO friendly set of easily navigatable pages. It can be used for comment threads, slideshows, or any kind of structured content.
The Idea
When called, the jQuery plugin splits the LI elements contained in the unordered list into a configurable number of groups. These groups (or pages) are floated to the left and hidden from view, as they overflow the UL which is given overflow:hidden. A number of control links are generated, which slide the appropriate page of LIs into view.
You can also take a look at the illustration below.
Step 1 – XHTML
The first step of the tutorial is to set up the XHTML markup. The plugin only needs an unordered list, UL, with some li elements inside it. Here is the code from demo.html, which you can find in the download archive:
demo.html
<div id="main">
<ul id="holder">
<li>Lorem ipsum dolor sit amet...</li>
<li>Lorem ipsum dolor sit amet...</li>
<li>Lorem ipsum dolor sit amet...</li>
<li>Lorem ipsum dolor sit amet...</li>
</ul>
</div>
The main div acts as a container for the paginated UL, and is styled with a nice light-gray background. The unordered list holds the list elements (hence the id).
In most practical situations, the markup above would probably be generated by a back-end script, freeing you from having to do it manually. You could have all sorts of content inside those LIs, as the height and size is dynamically calculated by jQuery (just a reminder – if you plan on using images, specify the width and the height).
Step 2 – CSS
After creating the XHTML markup, we can move on to styling it. If is a good idea to style your pages as if there were no navigation, as the plug-in is JavaScript dependent. This means that it is possible that some users will not be able to see nor use the pagination.
styles.css – Part 1
#main{
/* The main container div */
position:relative;
margin:50px auto;
width:410px;
background:url('img/main_bg.jpg') repeat-x #aeadad;
border:1px solid #CCCCCC;
padding:70px 25px 60px;
/* CSS3 rounded cornenrs */
-moz-border-radius:12px;
-webkit-border-radius:12px;
border-radius:12px;
}
#holder{
/* The unordered list that is to be split into pages */
width:400px;
overflow:hidden;
position:relative;
background:url('img/dark_bg.jpg') repeat #4e5355;
padding-bottom:10px;
/* CSS3 inner shadow (the webkit one is commeted, because Google Chrome
does not like rounded corners combined with inset shadows): */
-moz-box-shadow:0 0 10px #222 inset;
/*-webkit-box-shadow:0 0 10px #222 inset;*/
box-shadow:0 0 10px #222 inset;
}
.swControls{
position:absolute;
margin-top:10px;
}
First we style the main div and the unordered list (the latter is assigned the id of holder).
Notice how we use the CSS3 box shadow property with the inset attribute, to mimic an inner shadow. As with most CSS3 rules, we still have to provide vendor-specific prefixes for Mozilla (Firefox) and Webkit browsers (Safri and Chrome).
You can see that the webkit version of the property is commented out. This is because there is a bug in the rendering of box shadows in Chrome, when combined with the border-radius property (the shadows are rendered as if the div is square, ignoring the rounded corners and thus ruining the effect).
styles.css – Part 2
a.swShowPage{
/* The links that initiate the page slide */
background-color:#444444;
float:left;
height:15px;
margin:4px 3px;
text-indent:-9999px;
width:15px;
/*border:1px solid #ccc;*/
/* CSS3 rounded corners */
-moz-border-radius:7px;
-webkit-border-radius:7px;
border-radius:7px;
}
a.swShowPage:hover,
a.swShowPage.active{
background-color:#2993dd;
/* CSS3 inner shadow */
-moz-box-shadow:0 0 7px #1e435d inset;
/*-webkit-box-shadow:0 0 7px #1e435d inset;*/
box-shadow:0 0 7px #1e435d inset;
}
#holder li{
background-color:#F4F4F4;
list-style:none outside none;
margin:10px 10px 0;
padding:20px;
float:left;
/* Regular CSS3 box shadows (not inset): */
-moz-box-shadow:0 0 6px #111111;
-webkit-box-shadow:0 0 6px #111111;
box-shadow:0 0 6px #111111;
}
#holder,
#holder li{
/* Applying rouded corners to both the holder and the holder lis */
-moz-border-radius:8px;
-webkit-border-radius:8px;
border-radius:8px;
}
.clear{
/* This class clears the floated elements */
clear:both;
}
In the second part of the code, we style the page control links and the li elements. As you can see on line 46, we are applying rounded corners to both the unordered list and the li elements in one declaration, which saves us a from duplicating code.
Lastly is the clear class, which is used to clear the floats of the elements, also known as the clearfix technique.
Step 3 – jQuery
Moving to the last part of the tutorial, we need to include the latest version of the jQuery library in the page. Performance-wise, it is best to include all external JavaScript files just before the closing body tag, as scripts block he rendering of the page.
script.js – Part 1
(function($){
// Creating the sweetPages jQuery plugin:
$.fn.sweetPages = function(opts){
// If no options were passed, create an empty opts object
if(!opts) opts = {};
var resultsPerPage = opts.perPage || 3;
// The plugin works best for unordered lists,
// although OLs would do just as well:
var ul = this;
var li = ul.find('li');
li.each(function(){
// Calculating the height of each li element,
// and storing it with the data method:
var el = $(this);
el.data('height',el.outerHeight(true));
});
// Calculating the total number of pages:
var pagesNumber = Math.ceil(li.length/resultsPerPage);
// If the pages are less than two, do nothing:
if(pagesNumber<2) return this;
// Creating the controls div:
var swControls = $('<div class="swControls">');
for(var i=0;i<pagesNumber;i++)
{
// Slice a portion of the li elements, and wrap it in a swPage div:
li.slice(i*resultsPerPage,(i+1)*resultsPerPage).wrapAll('<div class="swPage" />');
// Adding a link to the swControls div:
swControls.append('<a href="" class="swShowPage">'+(i+1)+'</a>');
}
ul.append(swControls);
Creating a jQuery plug-in is not as hard as you might think. We just need to create a new function as a property of jQuery.fn (or $.fn, as given here). The this of the function points to the original jQuery object that it was called on.
Moving from there, we check for the existence of the opts object and set resultsPerPage accordingly. This is the number of li elements that are going to be grouped as a page.
After this, we calculate the total number of pages with the Math.ceil() function. It rounds the result to the nearest greater integer, which gives the correct number of pages.
Now that we have the number of pages obtained, we can enter a for loop in which we split the li elements into portions and wrap them in a swPage div, forming a page. Keep in mind that calling the jQuery slice() method on line 36 creates a new set of elements and leaves the original set intact (thus in every iteration of the for loop we start with the original set of li elements).
script.js – Part 2
var maxHeight = 0;
var totalWidth = 0;
var swPage = ul.find('.swPage');
swPage.each(function(){
// Looping through all the newly created pages:
var elem = $(this);
var tmpHeight = 0;
elem.find('li').each(function(){tmpHeight+=$(this).data('height');});
if(tmpHeight>maxHeight)
maxHeight = tmpHeight;
totalWidth+=elem.outerWidth();
elem.css('float','left').width(ul.width());
});
swPage.wrapAll('<div class="swSlider" />');
// Setting the height of the ul to the height of the tallest page:
ul.height(maxHeight);
var swSlider = ul.find('.swSlider');
swSlider.append('<div class="clear" />').width(totalWidth);
var hyperLinks = ul.find('a.swShowPage');
hyperLinks.click(function(e){
// If one of the control links is clicked, slide the swSlider div
// (which contains all the pages) and mark it as active:
$(this).addClass('active').siblings().removeClass('active');
swSlider.stop().animate({'margin-left': -(parseInt($(this).text())-1)*ul.width()},'slow');
e.preventDefault();
});
// Mark the first link as active the first time the code runs:
hyperLinks.eq(0).addClass('active');
// Center the control div:
swControls.css({
'left':'50%',
'margin-left':-swControls.width()/2
});
return this;
}})(jQuery);
In the second part of the script, we loop through the newly created pages, set their sizes and float them to the left. In the process we also find the tallest page, and set the height of the ul accordingly.
We also wrap the pages inside a swSlider div, which is wide enough to display them side by side. After this we listen for the click event on the control links, and slide the swSlider div with the animate method. This creates the slide effect that, observed in the demo.
script.js – Part 3
$(document).ready(function(){
/* The following code is executed once the DOM is loaded */
// Calling the jQuery plugin and splitting the
// #holder UL into pages of 3 LIs each:
$('#holder').sweetPages({perPage:3});
// The default behaviour of the plugin is to insert the
// page links in the ul, but we need them in the main container:
var controls = $('.swControls').detach();
controls.appendTo('#main');
});
In the last part of the code, we just a call to the plugin and passing the perPage setting . Also notice the use of the detach method, introduced in jQuery 1.4. It removes elements from the DOM, but leaves all the event listeners intact. It enables us to move the controls outside of the UL they were originally inserted in, keeping the click functionality in place.
With this our sweet pagination solution with jQuery and CSS3 is complete!
Conclusion
With this plugin you can power any kinds of comment threads, slideshows, product pages or other kinds of data. The advantage is that if JavaScript is disabled you still end up with a semantic and SEO friendly code. However if you plan to display huge chunks of data, it is still best to implement a back-end solution, as with the plug-in all the content is transferred to the visitor’s browser.
What do you think? How would you use this code?
http://tutorialzine.com/2010/05/sweet-pages-a-jquery-pagination-solution/


0 comentários: