Responsive Navigation Bar with mobile menu using HTML & CSS
Any website on the web should be responsive in the modern web era. One of the must-do task is to create a navigation bar which is usable on both huge 4K monitors and small mobile devices. And this is exatly what we'll create in this tutorial.
Video tutorial
If you prefer to watch a a step-by-step, beginner friendly video instead, you can check out the video that I made on my YouTube channel:
Implementing the HTML
The HTMl markup will be really simple and will consist of two separate sections. We'll first create the markup that will be used for the desktop version, and after that we will implement the markup required for the mobile menu.
HTML markup for the desktop version
We wrap everything inside of header
tags, and it will make our site more accessible as it helps screen readers. Inside the header we'll place a logo. For the sake of this example this will be a simple text wrapped inside an a
tag, which navigates to the homepage. Below the brand div, we will have a nav
wrapper. It also helps screen readers to understand the page. Inside our nav
we'll have an unordered list, which will hold all of our navigation links. Every navigation link will have the same basic structure. Each of them will be a list item (li
), and inside that we will have an a
tag which links to separate pages. I'll also give an id to the login and signup navigation for further styling.
<header>
<div id="brand"><a href="/">MyCompany</a></div>
<nav>
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
<li id="login"><a href="/login" >Login</a></li>
<li id="signup"><a href="/signup">Signup</a></li>
</ul>
</nav>
</header>
HTML markup for the mobile version
At small screen sizes, we will use a hamburger menu to toggle the navigation menu. For the hamburger icon you can use any external icon libraries, like FontAwesome, but in this tutorial, I'll create my own hamburger icon using HTML and CSS.
The hamburger icon 🍔
The html structure of the icon will be really simple. First we'll add a container div with the id of hamburger-icon
. We will use this wrapper div to style and positions the bars inside the hamburger icon. We'll also add an onclick
event handler, which will toggle our mobile menu. We'll implement this later in javascript. Inside our container we'll add three divs. They have separate classnames, and we'll use those for makeing our micro animation which will fade away the middle bar and form an X
from the bottom and top one.
<div id="hamburger-icon" onclick="toggleMobileMenu(this)">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
</div>
In CSS, we'll center the icon vertically using margin: auto 0
, and hide it by default using display: none
. We'll make it visible through a media query if the screen is less than 600px wide. (You can also do it in a mobile first approach and show it by default and hide it if the screen is wider than 600px). We'Ll give the divs inside the wrapper a fixed width and height and give them a little vertical spacing with margin. When the mobile menu is open (open
class is added to the mobile menu), we'll rotate the first bar by -45 degrees and adjust it with translate. We'll hide the second bar by setting the opacity to zero, and we'll also do the same transformations to the last element as we did for the first, but in the opposite direction.
#hamburger-icon {
margin: auto 0;
display: none;
cursor: pointer;
}
#hamburger-icon div {
width: 35px;
height: 3px;
background-color: white;
margin: 6px 0;
transition: 0.4s;
}
.open .bar1 {
-webkit-transform: rotate(-45deg) translate(-6px, 6px);
transform: rotate(-45deg) translate(-6px, 6px);
}
.open .bar2 {
opacity: 0;
}
.open .bar3 {
-webkit-transform: rotate(45deg) translate(-6px, -8px);
transform: rotate(45deg) translate(-6px, -8px);
}
Mobile HTML markup
Below the bars that we created for the hamburger icon in the previous section, we'll add the same navigation menu that we had in the desktop HTML markup section. The only important difference is that the unordered list has a class mobile-menu
. We will use this class to apply all the mobile related styles.
<div id="hamburger-icon" onclick="toggleMobileMenu(this)">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
<ul class="mobile-menu">
<li><a href="/home">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
<li id="login"><a href="/login" >Login</a></li>
<li id="signup"><a href="/signup">Signup</a></li>
</ul>
</div>
Finishing up the HTML.
There is two things we have to add:
- A link to the css stylesheet in the head section that we'll create:
<link rel="stylesheet" href="styles.css" />
- Importing our javascript file at the end of the body:
<script src="index.js"></script>
Implement the CSS part
First I'll import a Google font called Poppins, then reset every browser default margins and paddings and also set the box-siting to border-box. Then for the body we'll set out brand new font and set a dark background and white text color.
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap");
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
background-color: #353836;
color: white;
font-family: "Poppins", sans-serif;
}
Next we'll focus on the header wrapper and the logo. We'll remove all text decoration (underline) from any links inside the header. For the header we'll set a little bit of left and right padding, give it a dark background color, and a fixed height. We'll also set the display to flex, and to have the logo on the right and the navigation links on the left we'll add justify-content: space-between;
. For the brand, we'll set the desired font size and weight, and also center it vertically using flexbox.
header a {
text-decoration: none;
}
header {
padding: 0 20px;
background-color: #1d1f1d;
height: 50px;
display: flex;
justify-content: space-between;
}
#brand {
font-weight: bold;
font-size: 18px;
display: flex;
align-items: center;
}
#brand a {
color: #09c372;
}
Regarding the navigation links we'll remove any bullet points from the list, make the container full width and center it vertically using flexbox. We'll set a white color for the links and add some spacing using paddings and margins to the list items. I'll also add a hover effect to scale the links up a bit when they are hovered.
ul {
list-style: none;
height: 100%;
display: flex;
align-items: center;
justify-content: space-around;
}
ul a {
color: white;
}
ul li {
padding: 5px;
margin-left: 10px;
}
ul li:hover {
transform: scale(1.1);
transition: 0.3s;
}
The login and signup links will have a different button-like styling. We'll give them more spacing and round borders and use blue and red colors to differentiate them from the other links.
#login,
#signup {
border-radius: 5px;
padding: 5px 8px;
}
#login {
border: 1px solid #498afb;
}
#signup {
border: 1px solid #ff3860;
}
#signup a {
color: #ff3860;
}
#login a {
color: #498afb;
}
Now it's time to implement the styles for the mobile menu. By default the menu will be hidden so we'll apply display: none;
. We'll position the mobile menu absolutely, and place it right below the header, to do that we have to set a top offset of 50px, as it is the fixed height of the header. We want the mobile menu to take the full remaning space of the site (besides the header), so will make it full width, and we'll set the high to be 100% and substract the height of the header from it.
When the mobile menu is open, we want to display it, and we'll use flexbox to overrode the display:none
. We'll use flex-direction column to stack the links below each other, center them horizontally and make them start from the beginning of the flex container. We'll also add a little bottom margin to the links to amke them a little space to breath.
.mobile-menu {
display: none;
position: absolute;
top: 50px;
left: 0;
height: calc(100vh - 50px);
width: 100%;
}
.open .mobile-menu {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
.mobile-menu li {
margin-bottom: 10px;
}
Lastly we have to add the media query to hide the desktop menu, when we are on mobile size and display the hamburger icon when we are on mobile screen size. I'll use 600px as the breakpoint for mobile.
@media only screen and (max-width: 600px) {
header nav {
display: none;
}
#hamburger-icon {
display: block;
}
}
A little bit of javascript
We will have one lonely javascript function in our index.js file that will toggle the mobile menu between open and closed states. We already added this event handler in the HTML section. We will use the reference that we passed from the HTML and modify its classList using it. The toggle function will check wether the provided class is present on the element and if it is then it will remove it and if it's not then it will add it.
function toggleMobileMenu(menu) {
menu.classList.toggle('open');
}
Links for the full source code
You can check the full source code here:
- [Codesandbox link] (https://codesandbox.io/s/agitated-tu-97n1i?file=/index.js:0-70)
- GitHub repository
Where you can learn more from me?
I create education content covering web-development on several platforms, feel free to 👀 check them out.
I also create a newsletter where I share the week's or 2 week's educational content that I created. No bull💩 just educational content.
🔗 Links:
- ☕️ Support free education and my work, buy me a coffee
- 💬 Join our community on Discord
- 📧 Newsletter Subscribe here
- 🎥 YouTube Javascript Academy
- 🐦 Twitter: @dev_adamnagy
- 📷 Instagram @javascriptacademy