Build a mobile-first, collapsible navbar
Last updated: October 25, 2021.
In this tutorial, we will cover how to make a responsive navigation bar using HTML, CSS and vanilla JavaScript. Bootstrap offers a popular ‘out of the box’ navbar solution, but this involves importing a lot of CSS that could conflict with your own project’s styling. With a custom navbar, you have full control over styling and behaviour.
What we will build
Below is a live preview of what we will build in this tutorial:
See the Pen Untitled by James (@openjavascriptadmin) on CodePen.
Step 1: Add font awesome CDN
This tutorial uses font awesome icons for the navbar logo and toggle button. Make sure to include this link in the head of your HTML for these to be visible:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"/>
Step 2: HTML markup
Inside the HTML bogs tags, we wrap the entire content of our navbar inside a nav
element.
The first child inside of the container is a div with the id of nav-container
. This contains all elements that will be shown by default on a small screen. It contains two children: the website logo and a button to toggle navigation (we will program this functionality later).
The second child of the nav-container
is a ul
element containing each of the main menu items as li
elements.
The third child of nav-container
is the social media icons also as a ul
element with nested li
elements for each icon.
As we take a mobile-first approach, we want to hide the main menu items and social media icons by default as these should not appear in a small-screen view. For this, we need to add some CSS.
<nav id="nav-container"> <!-- wrapper for small screen elements --> <div id="small-sreen-elements"> <i id="logo" class="fas fa-terminal"></i> <button id="toggle-nav-button"> <i class="fas fa-bars"></i> </button> </div> <!-- NAVIGATION MENU ITEMS are, by using CSS media queries, not visible on a small screen by default and visible on a large screen. On a small screen, they are made visible when a user clicks the toggle navigation button by JavaScript adding a CSS class to the menu items making them visible --> <!-- Main menu items --> <ul class="menu-items"> <li> <a href="#">Home</a> </li> <li> <a href="#">About</a> </li> <li> <a href="#">Projects</a> </li> <li> <a href="#">Contact</a> </li> </ul> <!-- Social media items --> <ul class="social-icons"> <li> <a href="#"><i class="fab fa-facebook"></i></a> </li> <li> <a href="#"><i class="fab fa-twitter"></i></a> </li> <li> <a href="#"><i class="fab fa-instagram"></i></a> </li> <li> <a href="#"><i class="fab fa-linkedin"></i></a> </li> </ul> </nav>
Step 3: Adding mobile-first CSS
As we take a mobile-first approach, in our CSS we specify how we want our navbar to appear on a small screen before using CSS media queries to make edits to the styling for a larger screen.
For a smaller screen we add the following.
Note that we apply flexbox to the small-screen-elements
div with justify-content
set to space-between
so that the logo and toggle navigation button are pushed to opposite ends of the navbar.
And importantly, both the main menu items and social media icons (the second and third children within the nav container) are hidden from view so that only the small-screen-elements
are visible.
But we do not set the main menu items ul
element to display: none
. Instead, we set height to 0px
and overflow to hidden
. To see its contents, all we then need to do is give it a height. We will do this dynamically by adding a CSS class to give the main menu items a height when the user clicks the toggle navigation button.
/* Style the nav (always the same) */ nav { background-color: #d9138a; } nav ul { list-style-type: none; } nav a { font-family:sans-serif; text-decoration: none; color: whitesmoke } /* Style navbar for small screen */ #small-sreen-elements { display: flex; justify-content: space-between; align-items: center; padding: 1rem; } #toggle-nav-button { font-size: 1.5rem; margin-top: 0.4rem; color: white; background-color: transparent; border-color: transparent; cursor: pointer; } #logo { font-size: 2rem; color: rgb(30,30,30); padding-top: 0.8rem; padding-left: 1rem; } /* Style menu items */ /* Default class (no display) */ .menu-items { height: 0; overflow: hidden; background-color: #322e2f; } .menu-items a { display: block; padding-top: 2rem; font-size: 1rem; margin-left: 1rem; margin-right: 1rem; } /* No social icons */ .social-icons { display: none; }
The CSS styling we will add to the main menu items ul
element is the following:
.show-menu-items { height: 15rem; }
Add this to the CSS above. We are now ready to add JavaScript to get the toggle button working.
Step 4: Add JavaScript
First, we select the toggle navigation button and the menu items ul
and store both in variables.
Next we add an event listener to the navigation toggle button that listens for a user click. When this is clicked, the toggleNav
functions fires. This toggles the show-menu-items
class element on the class list of the menu ul
(toggle adds it to the class list if not present and removes it if present).
// Get toggle button and menu items ul const toggleBtn = document.getElementById('toggle-nav-button'); const menuItems = document.querySelector('.menu-items'); // When toggle button pressed, run toggleNav function toggleBtn.addEventListener('click', toggleNav); function toggleNav() { menuItems.classList.toggle('show-menu-items'); }
Clicking on the navigation toggle button now toggles the menu!
All we need to do now is add a media query to our CSS so that our menu is also appropriate for larger screens.
Step 5: Adding a media query for larger screens
To make our navigation display well on large screens, we add a media query. We specify a min-width of 700px
. For screens larger than this, we want a different layout.
Now, display: flex
and justify-content: space-between
is applied to the navbar wrapper so its three children are pushed to the far-left, middle and far-right of the container.
For a larger screen size, we make the menu items and social media icons visible by applying display: flex
and the height of the menu items to auto
(by default 0).
@media screen and (min-width: 700px) { /* Now apply flex to entire container */ #nav-container { display: flex; justify-content: space-between; align-items: center; padding: 1rem; } /* Hide toggle button */ #toggle-nav-button { display: none; } /* Flex for menu items */ .menu-items { height: auto; display: flex; flex-direction: row; background-color: #d9138a; } /* Remove padding applied in vertical view*/ .menu-items li a { padding-top: 0rem; } /* Social icons now visible */ .social-icons { display: flex; flex-direction: row; } .social-icons a { margin-right: 0.8rem; } #logo { padding: 0; }
Your navigation bar should now adapt to larger screens from a logo and toggle navigation button to logo, main menu items and social media icons.
Summary
In this tutorial we have seen how to code a mobile-first collapsible navbar using HTML, CSS and JavaScript.
Liked this project? Head to our project section for more HTML, CSS and JavaScript projects of varying difficulty.