Design Method
Creating a CSS3 Navigation Menu
In today’s tutorial, I thought a good topic to cover would be the creation of a custom navigation menu using CSS3. The purpose of this tutorial is to further familiarise ourselves with CSS3 and Less, as well as have to an attractive navigation at the end that you’ll hopefully be able to integrate into your own website or projects.
First, let’s take a look at what we’re building:
Please note that before proceeding, it’d be best if you have some knowledge of CSS3 animations and Less. If you aren’t familiar with these, I urge you to read 2 of our previous posts, CSS3 Animation Tutorial and An Introduction to Less CSS.
In addition, this tutorial assumes that you’re relatively experienced with HTML and CSS. I will therefore only be covering certain aspects of the code.
Getting Started
Let’s start by building a simple unordered list within the HTML5 <nav>
element. We’ll ignore the labels, sub-menus and animation for now.
[html]
<nav>
<ul>
<li id="home">
<a href="#">Home</a>
</li>
<li id="about">
<a href="#">About</a>
</li>
<li id="services">
<a href="#">Services</a>
</li>
<li id="gallery">
<a href="#">Gallery</a>
</li>
<li id="contact">
<a href="#">Contact</a>
</li>
</ul>
</nav>
[/html]
As you saw in the demo, what we want is for the navigation to be positioned at the top left of the page, and for each of it’s navigation items to be stacked vertically.
Positioning the navigation is simple enough:
[css]
nav{
position: absolute;
top: 20px;
left: 20px;
// Additional styles
font-size: 13px;
text-transform: uppercase;
}
[/css]
We can then go ahead and apply CSS to the rest of the HTML:
[css]
// Set variables
@navBoxSize: 40px;
@navStrokeWidth: 1px;
nav{
position: absolute;
top: 20px;
left: 20px;
font-size: 13px;
text-transform: uppercase;
li{
list-style: none;
}
> ul{
margin: 0;
padding: 0;
> li{
display: block;
width: @navBoxSize;
height: @navBoxSize;
line-height: @navBoxSize;
text-align: center;
margin-top: 10px;
&:first-child{
margin-top: 0;
}
a{
display: block;
width: 100%;
height: 100%;
color: #fff;
text-decoration: none;
}
>a{
border-width: @navStrokeWidth;
border-style: solid;
}
}
}
}
[/css]
Hopefully most of the above will make sense. Below are some of the key points:
- On lines 2-3 I’ve set 2 variables, one for the size of the squares and one for the width of the border that should be applied. I could have hard-coded this into the CSS, but doing it this way means that I can easily change the appearance of the box at a later date.
- I’ve used a mixture of child combinator selectors and more generic selectors to define what styles should cascade down to the sub-menu (which we will add in a bit). For example, between lines 27-37, you’ll notice 2 different sets of styles for the links, as I don’t want the sub-menu links to have borders.
Some of you may have noticed that I’ve set a border width and style to the some of the links, but haven’t yet added any colour. That’s actually the next step we’re going to cover, and we’re going to use some cool Less functions!
Adding Colour
In the demo, each of the navigation items is different colour. In addition, there are 2 shades used; for example the Gallery link has a light orange background with a dark orange border.
Again, a situation like this is perfect for Less variables, especially when you start adding sub-menus utilising the same colours!
So the next step is to define some additional variables to hold the hex value for each background colour:
[css]
@navColorHome: #0891cb; // Dark blue
@navColorAbout: #3bc2fc; // Light blue
@navColorServices: #31ae0a; // Green
@navColorGallery: #ff9600; // Orange
@navColorContact: #ff5831; // Red
[/css]
But how about the darker shades used for the borders and mouse over effect of the sub-menu? The laborious way would be to find other colours manually, and prior to CSS pre-processors like Less and Sass, this would have actually been the only option.
Luckily for us, CSS pre-processors do now exist and they have a wide range of helper functions. In this case, the function we’re interested in is darken()
.
The darken()
function takes 2 parameters:
- Colour – An HSL (Hue, Saturation, Lightness) object of the base colour.
- Amount – A percentage to darken the colour by.
Looking at the above, it’s apparent that we need to somehow create the HSL object from our hex values. Less has functions for that too:
hue()
– Extracts the hue channel of a colour object in the HSL colour space.saturation()
– Extracts the saturation channel of a colour object in the HSL colour space.lightness()
– Extracts the lightness channel of a colour object in the HSL colour space.hsl()
– Creates an opaque colour object from hue, saturation and lightness (HSL) values.
Using a combination of the above functions, we can get Less to automatically generate an appropriate colour for each navigation item. To clarify this, see the code below:
[css]
// Set colours
@navColorHome: #0891cb;
@navColorAbout: #3bc2fc;
@navColorServices: #31ae0a;
@navColorGallery: #ff9600;
@navColorContact: #ff5831;
// Calculate other colours
@navColorHomeDark: darken(hsl(hue(@navColorHome), saturation(@navColorHome), lightness(@navColorHome)), 10%);
@navColorAboutDark: darken(hsl(hue(@navColorAbout), saturation(@navColorAbout), lightness(@navColorAbout)), 20%);
@navColorServicesDark: darken(hsl(hue(@navColorServices), saturation(@navColorServices), lightness(@navColorServices)), 6%);
@navColorGalleryDark: darken(hsl(hue(@navColorGallery), saturation(@navColorGallery), lightness(@navColorGallery)), 8%);
@navColorContactDark: darken(hsl(hue(@navColorContact), saturation(@navColorContact), lightness(@navColorContact)), 15%);
[/css]
If you ever need to change the colour of a navigation item in the future, you now only need to change the hex values at the top and Less will handle the rest. How awesome is that?
It’s worth noting that I’ve actually gone ahead and tweaked the percentage values (the last parameter) to suit my tastes.
Adding Icons with Font Awesome
We’ve now got a navigation that comprises of vertically stacked boxes of differing colours. What we don’t have are icons; instead we have text which flows out of the boxes.
Let’s go ahead and fix that! We’re going to use Font Awesome for our icons.
Font Awesome is an iconic font set that gives you scalable vector icons. It’s a font, so you can apply CSS to it like any other text. You can change the colour, add text shadow etc… Needless to say, it’s super useful! I’m not sure if I explained that very well, but it’ll become very clear shortly.
First things first, how do we install Font Awesome onto our website? Just paste the following in the <head>
section of your HTML:
And you’re now all set to use Font Awesome on your website! You can use the following to add icons to your website. For example for the icon, use:
The first class above is the generic class that must be used on all Font Awesome icons. The second class then specifies which particular icon to show. There are a wide variety of icons you can use; you can take a look at the cheatsheet to see what’s available. It’s also worth a looking at their examples, as it’ll show you how to do things like this .
Ok, so let’s integrate Font Awesome into our navigation:
[html]
<nav>
<ul>
<li id="home">
<a href="#"><i class="fa fa-home"></i></a>
</li>
<li id="about">
<a href="#"><i class="fa fa-info"></i></a>
</li>
<li id="services">
<a href="#"><i class="fa fa-camera"></i></a>
</li>
<li id="gallery">
<a href="#"><i class="fa fa-th"></i></a>
</li>
<li id="contact">
<a href="#"><i class="fa fa-comments-o"></i></a>
</li>
</ul>
</nav>
[/html]
As aforementioned, the Font Awesome icons are fonts, and therefore we don’t need to touch the CSS. It’ll look the same as the previous text did, i.e. white, no text decoration etc…
Finishing It Off
We’re now pretty much there with our navigation. The rest of it is pretty standard, i.e. nest the sub-menu, add some hover over effects, and some CSS3 animation to give it a little more flare.
Below is a link so that you can download & inspect the entire code. You may notice that I’ve used the HTML5 Boilerplate, which I will cover in a later Tutorial Tuesday post!