News

Unleash CSS to build smart fixed navigation

SmartFixedCSSMenu

Give your visitors a distraction-free way to read your website’s content without the permanent presence of a menu

SmartFixedCSSMenu

As a 25-year-old, you’d expect the World Wide Web to have matured into a fully rounded adult by now; to know how to interact with others properly, to mind its manners and to understand which cutlery to use and when during meals.

As developers we all shape the user’s experience of the World Wide Web. The decisions you make and the effort that you put in will determine whether your particular part of WWW will work properly on a range of devices and whether your code will follow agreed practices and accessibility standards. Providing users with the right tools to use at the right time also has a big impact on usability.

As a core design principle if something isn’t needed, it simply shouldn’t be there. Dine at nearly any restaurant and your waiter will helpfully take away your menu whilst you enjoy your meal, but happily bring it back if you want to consider a dessert. By adding a smart menu to your website, you can tuck your menu discreetly out of the way and let your user concentrate on enjoying the main course. If they need something else, the menu is just a click away.


GET THE CODE FOR THIS TUTORIAL


Set the scene

This tutorial is about adding a smart menu as a refinement to the user experience, but in order for that to be effective you’ll want to provide other user refinements along the way. The right choice of font to suit your content and audience is a must. You should also try adding and removing the font-smoothing code to see the difference it makes.

001 @import url(http://fonts.googleapis.com/css?family=Maven+Pro);
002 * {
003  -webkit-font-smoothing: antialiased;
004  -moz-osx-font-smoothing: grayscale;
005 }
006
007 html { 
008  background: url(../img/bg.jpg) no-repeat center center fixed; 
009  -webkit-background-size: cover;
010  -moz-background-size: cover;
011  -o-background-size: cover;
012  background-size: cover;
013 }

Tweak that body

Experiment with different font-sizes, line-heights and paragraph spacing until you achieve the best look for your page. Many designers suggest that you avoid using the extremes of black and white to achieve a more aesthetically pleasing result. #eee will give you a nearly white result but just take the edge off any harshness.

001 body {
002  font-family: ‘Maven Pro’, sans-serif;
003  font-size: 25px;
004  line-height: 35px;
005  color: #eee;
006 }
007
008 p {
009  margin-bottom: 50px;
010  text-align: justify;
011 }
012
013 a {
014  color: #efbe5d;
015  text-decoration: none;
016  text-transform: uppercase;
017 }

Room to breath

Use of space is important in usability and also in setting your user’s expectations about the ‘weight’ of the content. Encourage your user to start reading by using plenty of space, especially around headings. Whilst this tutorial doesn’t attempt to provide a fully responsive solution, you should consider how your titles will look if they are forced to wrap in narrower viewports.

001 header {
002  margin: 100px 0 100px;
003 }
004 h1 {
005  font-size: 50px;
006  text-align: center;
007  line-height: 50px;
008 }
009
010 h2 {   
011  color: #efbe5d;
012  text-align: center;
013  text-transform: uppercase;
014  border:1px solid #ccc;
015  border-width:0 0 1px 0;    
016  margin-bottom: 20px;
017  }

Main menu style

For consistency and economy of code the main and side menu share much of the same styling rules. Border-width: 1px 0; will create a border at the top and bottom but no border to the left or right. If you’re unsure what a particular piece of code does, take it out and see what happens (even the most experienced developer has done this at some point).

001 #nav{
002    border:solid #ccc;
003    border-width:1px 0;
004    list-style:none;
005    margin:0 0 50px;
006    padding:0;
007    text-align:center;
008 }
009
010 #nav a {
011    display:inline-block;
012 }
013

Position the paragraphs

A max-width percentage is applied to avoid excessively long line-lengths on large screens but provide some flexibility to the layout. A reasonably sized margin is needed down the side to accommodate the side menu. Margin: 0 auto; is used to centre the paragraph text horizontally on the page.

001 #wrapper {
002  max-width: 60%;
003  margin: 0 auto;
004  }
005 #cd-nav li {
006    display: inline;    
007  }
008 #cd-nav li a {
009    padding: 15px;
010  }
011 #cd-nav li a:hover {
012    color: #eee;
013  }
014

Menu ready

When the user scrolls down the page, the .is-fixed class is added to the #cd-nav div. in readiness for displaying the menu. It’s not needed until the user clicks on the icon though so it is scaled to 0% and waits
until it is called for.

001 #cd-nav.is-fixed ul {
002    position: fixed;
003    max-width: 125px;
004    transform: scale(0);
005 }
006

Now you see me

Steps seven and eight manage the positioning, appearance and disappearance of the side menu.
The menu icon is positioned conveniently half way down the viewport. You’ll want to tweak the top and margin-top settings to suit the height of your own menu and those settings have been adjusted here so that the whole menu is still visible even when the viewport height is significantly reduced.

001 #cd-nav ul.is-visible {
002 2   transform: scale(1);
003   transition: transform 0.3s, visibility 0s 0s;
004  }
005 #cd-nav ul.has-transitions {
006    right: 5%;
007    top:40%;
008    margin-top: -135px;
009    transition: transform 0.3s, visibility 0s 0.3s;
010  }  

Now you don’t

ul.is-visible displays the menu when the icon is clicked, ul.has-transitions hides the menu if the icon is clicked whilst the menu is open. ul.is-hidden hides the menu when the page is scrolled past a preset point towards the top of the page.

001 #cd-nav ul.is-hidden {
002    transform: scale(0);
003    transition: transform 0.3s;
004  }

Style and position the menu icon background

It’s easy to change the shape, size and position of this to suit your needs. If you are going to have your icon background flush against the page edge, it makes good visual sense to only put rounded corners on the edges that are not flush.

001 .cd-nav-trigger {
002  position: fixed;
003  top: 50%;
004  right: 0%;
005  width: 60px;
006  height: 60px;
007  border-radius: 25px 0 0 25px;
008  background: #efbe5d;
009  overflow: hidden;
010  text-indent: 100%;
011  white-space: nowrap;
012  z-index: 2;
013 }

Burger and cross

This neat little code forms the central part of the burger icon. Aside from being file-size friendly, this method enables the icon to be easily customisable and easily animated. It’s well worth experimenting with these settings and those in the next two steps to see how the technique works.

001 .cd-nav-trigger span {
002  position: absolute;
003  display: block;
004  width: 20px;
005  height: 3px;
006  background: #eee;
007  top: 50%;
008  margin-top: -1px;
009  left: 50%;
010  margin-left: -10px;
011  transition: background 0.3s;
012 }

Cross bars

These pseudo-elements start to set up the white bars that sit above and below the central bar. When the icon is clicked in its burger state, the central bar fades away and the top and bottom bars rotate to form a cross. It happens quite quickly so slow the animation down if you want to see what is going on more clearly.

001 .cd-nav-trigger span::before, .cd-nav- trigger span::after {
002  content: ‘’;
003  position: absolute;
004  left: 0;
005  background: inherit;
006  width: 100%;
007  height: 100%;
008  transform: translateZ(0);
009  backface-visibility: hidden;
010  transition: transform 0.3s, background 0s;
011 }
012

As above, so below

The -8px for top and bottom are setting the bars in place and their rotation is set to zero in anticipation of them being animated. The RGB setting is a neat way of turning an element invisible. The RGB values could be set to any value and still achieve the same effect, it’s the last 0 that sets the opacity to zero.

001 .cd-nav-trigger span::before {
002  top: -8px;
003  transform: rotate(0);
004 }
005 .cd-nav-trigger span::after {
006  bottom: -8px;
007  transform: rotate(0);
008 }
010 .cd-nav-trigger.menu-is-open span {
011  background: rgba(0, 0, 0, 0);
012 }
013

Create the cross

You can set the cross to any colour you wish here. Rotating bars by 135 degrees and 225 degrees causes them to intersect at 180 degrees to create the cross shape. You can have fun by setting a much higher rotate value and set the cross bars spinning.

001 .cd-nav-trigger.menu-is-open span::before, .cd-nav-trigger.menu-is-open span::after {
002  background: #eee;
003 }
004 .cd-nav-trigger.menu-is-open span::before {   top: 0;
005  transform: rotate(135deg);
006 }
007 .cd-nav-trigger.menu-is-open span::after {
008  bottom: 0;
009  transform: rotate(225deg);
010 }
011

Icon animation

The first part above removes the menu icon from the screen when the page is scrolled up. The second part sets up the animation. This is used when the icon’s appearance is triggered by scrolling down the screen.

001 .cd-nav-trigger {
002    visibility: hidden;
003    transform: scale(0);
004    transition: transform 0.3s, visibility 0s 0.3s;
005  }
006  .is-fixed .cd-nav-trigger {
007    visibility: visible;
008    transition: all 0s;
009    transform: scale(1);
010    animation: cd-bounce-in 0.3s linear;
011  }

Animations

Nearly 50 lines of code translate to five when vendor prefixes are removed, so check out the supplied files for the full code. This simple animation creates the bounce effect when it is triggered. The physics of the effect help make the menu seem more real.

001 @keyframes cd-bounce-in {
002  0% { transform: scale(0); }
003 60% { transform: scale(1.2); }
004 100% { transform: scale(1); }
005 }

HTML

Diving straight into the HTML, past the normal links to style sheets and the like, the menu icon is placed in the DOM but rendered invisible until it is required. To work correctly, the anchor link needs to be styled as a page anchor but shouldn’t be a valid link. The empty span tags enable the burger icon to be created.

001 <div id=”wrapper”>
002   <div id=”cd-nav”>
003 <a href=”#0” class=”cd-nav trigger”>Menu<span></span></a>
004    
005    <header>
006        <a name=”1”></a><h1>The Star by H G Wells</h1>
007    </header>

An unordered list

The navigation content is all created using the usual unordered html list. The class of “cd-main-nav” is applied to the navigation. This class is not specified in the style sheet, instead it forms part of the small jQuery file and is used to identify that element so that it can be manipulated by the jQuery.

001 <nav id=”cd-main-nav”>
002        <ul id=”nav”>
003                <li><a href=”#1”>ONE</a></li>
004                <li><a href=”#2”>TWO</a></li>
005                <li><a href=”#3”>THREE</a></li>
006                <li><a href=”#4”>FOUR</a></li>
007                <li><a href=”#5”>FIVE</a></li>
008        </ul>
009    </nav>
010 </div>
×