Create a navigation bar with an animated indicator
You have always wanted to create a dynamic navigation bar with an indicator that smoothly slides underneath the new page you are on? This navigation bar is exactly what you need!
Step 1: The HTML Code
To begin, let's create the HTML code that will allow us to set up our navigation bar.
<nav>
<a href="#">Home</a>
<a href="#">About</a>
<a href="#">Testimonials</a>
<a href="#">Blog</a>
<a href="#">Contact</a>
</nav>
Nothing too difficult to understand here. We have a <nav></nav>
tag grouping several links. Let's add a class .nav-item
to each link so that our different links can be styled more easily. We will then create a class with the same name to add some properties.
<nav>
<a href="#" class="nav-item is-active">Home</a>
<a href="#" class="nav-item">About</a>
<a href="#" class="nav-item">Testimonials</a>
<a href="#" class="nav-item">Blog</a>
<a href="#" class="nav-item">Contact</a>
</nav>
Note that we have also added a .is-active
class so that the current page is displayed differently. This is a visual marker that is very useful.
Step 2: The CSS Code
For our styling, we start with very simple code. Follow the comments to understand what we're doing.
/* Ensure each element includes its internal margin with box-sizing and remove the default link underlines */
* {
box-sizing: border-box;
text-decoration: none;
}
/* Modernize our navigation bar with a subtle shadow. Arrange all menu items side by side using flexbox (display: flex) */
nav {
background-color: #fff;
padding: 0 20px;
border-radius: 40px;
box-shadow: 0 10px 40px rgba(159, 162, 177, .8);
display: flex;
overflow: hidden;
overflow-x: auto;
position: relative;
}
/* Style each item */
.nav-item {
color: #83818c;
font-family: Arial, sans-serif;
padding: 20px;
margin: 0 6px;
position: relative;
}
/* Here we add a small element before each item to make it visually appealing */
.nav-item:before {
content: "";
position: absolute;
bottom: -6px;
background-color: #dfe2ea;
height: 5px;
width: 100%;
border-radius: 8px 8px 0 0;
left: 0;
transition: .3s;
}
/* With the latest CSS features, we can change the properties of elements based on conditions using :not */
.nav-item:not(.is-active):hover:before {
bottom: 0;
}
.nav-item:not(.is-active):hover {
color: #333;
}
/* Style our indicator */
.nav-indicator {
position: absolute;
left: 0;
bottom: 0;
height: 5px;
transition: .4s;
border-radius: 8px 8px 0 0;
}
Step 3: Finalize the HTML Part
Having a menu is great! But let's now try to modernize it with an indicator that moves according to the current page.
To achieve this, let's start by adding an HTML element using the <span></span>
tag inside our navigation bar to include an element that will move based on our current page.
<nav>
<a href="#" class="nav-item is-active" data-active-color="orange" data-target="Home">Home</a>
<a href="#" class="nav-item" data-active-color="green" data-target="About">About</a>
<a href="#" class="nav-item" data-active-color="blue" data-target="Testimonials">Testimonials</a>
<a href="#" class="nav-item" data-active-color="red" data-target="Blog">Blog</a>
<a href="#" class="nav-item" data-active-color="rebeccapurple" data-target="Contact">Contact</a>
<span class="nav-indicator"></span>
</nav>
We have almost finished our HTML! Let's finish by adding data attributes that can be retrieved by our JavaScript code: simply use data
attributes by specifying the desired name:
<nav>
<a href="#" class="nav-item is-active" data-active-color="orange" data-target="Home">Home</a>
<a href="#" class="nav-item" data-active-color="green" data-target="About">About</a>
<a href="#" class="nav-item" data-active-color="blue" data-target="Testimonials">Testimonials</a>
<a href="#" class="nav-item" data-active-color="red" data-target="Blog">Blog</a>
<a href="#" class="nav-item" data-active-color="rebeccapurple" data-target="Contact">Contact</a>
<span class="nav-indicator"></span>
</nav>
Our code is complete! Now let's move on to the JavaScript.
Step 4: The JavaScript Code
To start, it's very important to select our indicator and each of our items:
const indicator = document.querySelector('.nav-indicator');
const items = document.querySelectorAll('.nav-item');
Once our elements have been selected, we will detect events. What interests us most is the click event.
The JavaScript property
querySelectorAll
returns a NodeList that contains each of our items.
Therefore, all that's left is to use a forEach
loop to attach the event listener using addEventListener
, specifying that we want to call the handleIndicator
function.
This new handleIndicator
function will allow us to detect the link that was clicked to move the indicator (indicator).
const indicator = document.querySelector('.nav-indicator');
const items = document.querySelectorAll('.nav-item');
function handleIndicator(el) {
}
items.forEach((item, index) => {
item.addEventListener('click', e => {
handleIndicator(e.target)
});
item.classList.contains('is-active') && handleIndicator(item);
});
All that remains is to create the handleIndicator
function.
const indicator = document.querySelector('.nav-indicator');
const items = document.querySelectorAll('.nav-item');
function handleIndicator(el) {
// Loop through items and remove the "is-active" class
items.forEach(item => {
item.classList.remove('is-active');
item.removeAttribute('style');
})
const elementColor = el.dataset.activeColor;
const target = el.dataset.target;
// Style the indicator
indicator.style.width = `${el.offsetWidth}px`;
indicator.style.backgroundColor = elementColor;
indicator.style.left = `${el.offsetLeft}px`;
// Add the "is-active" class
el.classList.add('is-active');
el.style.color = elementColor;
}
items.forEach((item, index) => {
item.addEventListener('click', e => {
handleIndicator(e.target)
});
item.classList.contains('is-active') && handleIndicator(item);
});
Here's what we do for each clicked element:
- Remove the
.is-active
class from all elements: we reset the menu; - Retrieve the color of the clicked item using
dataset
, which allows us to read thedata
attribute; - Use this color to define the style of our indicator (indicator);
- Finally, add the
.is-active
class to the current page's element.
And that's it!
If you want to learn more, don't hesitate to follow our dedicated courses on JavaScript or React (if you are well-versed in JavaScript) to fully take advantage of your brand new menu created in this article!