Create stepped navigation with arrows using HTML + CSS

In this tutorial I will show you how to create a stepped navigation with arrows using HTML and CSS which works in all major browsers. It is useful to show a user a stepped process such as a multi part form where there is more than one step that needs to be filled in.

Step 1: The HTML

For the HTML we will use an unordered list so the navigation is accessible and will still partly work without the CSS file such as in text browsers.

<div class="steps">
li class="step step-1">
a href="#"><strong>Step 1</strong><br />Some random text that describes the step</a>
li class="step step-2">
a href="#"><strong>Step 2</strong><br />Some random text that describes the step</a>
li class="step step-3">
a href="#"><strong>Step 3</strong><br />Some random text that describes the step</a>

This will leave us with the following - view step 1 result.

Step 2: Style with CSS

We now need to make it pretty, firstly we reset the default CSS rules applied to unordered lists by the browsers.

.steps ul, .steps li {

This resets the margins and padding around each the list itself and each list element within the list as well as removing the list-style (i.e. the bullet).

To make the elements appear side-by-side rather than on top of one another, we need to float the list elements.

.steps ul floatleft; }
steps li {

This will leave you with your list elements side-by-side. View the result of step 2.

Step 3: Make the steps in to arrows

The next step is to add in our arrows to be background images.

<?php.steps li a {
  display: block;
  padding: 15px 20px;
  color: #fff;
  line-height: 1.5em;
  text-decoration: none;

This makes the anchor tags act like block level elements so that they fill out in to their parent item which is the <li>. We also add some padding and set the line-height to make it look nicer.

Next we add in the background images for our list elements. You can use these images for the time being to speed up the process, just right click them then save them in the same folder as your CSS file. Normal & Hover. The images are basic PNGs with transparent sections on the end of arrow. There is also a 1px stroke to the right which gives you the seperator between the steps. The images should be as wide as your container, the reason for this is mentioned in step 5.

<?php.steps li.step a { background: transparent url(step.png) center right no-repeat; }
.steps li.step a:hover { background: transparent url(step_over.png) center right no-repeat; }?>

This adds in the images to our steps with the hover state. View result of step 3

Step 4: Setting the width and aligning the steps

As you can tell from the result of step 3, we have a bit of a mess now. So now we can clear it up. My example is wrapped in a container which is 960px wide, so what I am going to do, is divide that by 3 as I have 3 steps. That means each step should be 320px wide. So alter the CSS for .steps li to the following:

.steps li {

This now lines our steps side-by-side again with the text wrapped to fit in the width, but the arrows are stop start and aren't covering each other.

To get around this, we use a negative margin to pull the element to the left, although we only apply this to the 2nd and 3rd steps.

<?php.steps li.step-2, .steps li.step-3 { margin-left: -30px; }?>

Now you will notice a new problem. The later steps are covering the earlier steps so the arrow isn't visible. To get around this, we will use the CSS property z-index to change the layering on the z-axis.

For z-index to be effective though, we also need to change the positioning type of the list element and child anchor.

<?php.steps li.step, .steps li.step a {
  position: relative;
  z-index: 3;
.steps li.step-2, .steps li.step-2 a { z-index: 2; }
.steps li.step-3, .steps li.step-3 a { z-index: 1; }?>

Once again we have created more problems. The first one being that some of the text is now hidden beneath the arrow of the preceeding step. We can get around this by adding some extra padding.

<?php.steps li.step-2 a, .steps li.step-3 a { padding-left: 50px; }?>

The 50px comes from the -30px which is the left negative margin + the extra 20px of padding we defined earlier on for each anchor element.

The negative margins also made the total width of our stepped element less than 960px so we have a gap at the end. With some simple maths we can work out the new width that each list element must be to fit the 960px width. We have a 960px container with 2 elements with negative margins of 30px, so 960px + 60px = 1020px. Now we divide that by 3 to get our new width which is 340px.

<?php.steps li {
  float: left;
  width: 340px;

This then leaves us a lot closer to our goal. View result of step 4.

Step 5: Fix the background position of the last step

The arrow is showing on the 3rd step although it doesn't go anywhere, it is the end. To fix this, we just need to change the background position for step 3, this is the reasoning for our images being long.

<?php.steps li.step-3 a { background-position: center left; }
.steps li.step-3 a:hover { background-position: center left; }?>

We change the background image to be aligned to the left so it is solid colour, as we made the images longer than the content, unless there is only 1 step (why would you be doing this tutorial if you only had 1 step?) the arrow won't be seen.

Then you have a finished stepped navigation. View result of step 5.

Then with a little extra CSS for text formatting and some borders on the parent element you are left with the final result.


[...] This post was mentioned on Twitter by James Tombs, James Tombs. James Tombs said: New HTML + CSS tutorial - #html #css [...]

Useful, I'll save it, thanks for sharing.

I am a beginner it will be useful for me thank you!

Step 2 does not float the elements side by side.

It should do. What browser are you using?

These really helped me to build my homepage, I can really appreciated if people take some time and write a usefull tutorial.

Hello there !
Thank you for this great article.
I've implemented it successfully. But I miss some stuff about the global border...
And the source code is no more avalaible...

Is there any way to get it somewhere ?

I have fixed the links.

hi, thank you for this great tutorial

would it be very difficult to have a current and visited state


Hi, thank you so much for this great tutorial.

Is there a way to get a current and visited state ?

Thank for any suggestions


You would just need to add an active class to the menu item and style it however you want. How you add the class will depend on how you are generating the HTML markup.

Thank you for this post, it helped me get over my fear of z-index and arrows, I'll save it too.