"How to make a collapsible nav bar with hamburger icon"
"How to make hamburger bar"
"Easy vanilla JS responsive navigation menu"
If these searches look familiar to you - and the disappointment that follows them is a feeling you're well acquainted with - then chances are, you're a newer coder who's looking to go mobile-responsive.
If we want users to stick around, we'll need our website to look gorgeous and work intuitively in a clean, organized way on ALL device sizes. If you've not lived under a rock for the last 10 years, then you've undoubtedly seen the "Holy Grail" of mobile-friendly features, the collapsible nav bar - sometimes referred to as a "Hamburger bar" for the fact that the most common icon we use to indicate it's presence is, in fact, shaped kind of like a hamburger.
The idea is simple.
When our app is displayed on a mobile device with a screen below a set size, our normal web page navigation bar, which might look something like this:
Desktop view of a bootcamp website
…will instead disappear and be replaced by this:
Mobile view of the same header - note that the icon is not a hamburger. You can use any icon you want! Just make sure users will intuitively understand what it's for!
Now our navigation bar won't take up the entire screen. When a user taps on that icon, our navigation bar should roll out smoothly below to display the list items - our links - in a column below.
So how do we do this? There are a dozen ways, probably, but I believe simplicity is the sturdiest foundation for quality engineering, so let's start with a very basic html template that can easily be built out later as needed:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
</head>
<body>
<nav>
<div class="hamburger">
<i class="material-icons">menu</i>
</div>
<ul class="nav-links">
<li><a href="index.html">Home</a></li>
<li><a href="page2.html">About</a></li>
<li><a href="somebody@someplace.com">Contact</a></li>
</ul>
</nav>
<script src="script.js"></script>
</body>
</html>
As you can see, it's pretty straightforward - but just in case, here's a breakdown of the code itself:
<!DOCTYPE html>
<html>
<head>
<!-- This will link our stylesheet to our index.html: -->
<link rel="stylesheet" type="text/css" href="styles.css" />
<!-- This will link the google icon for our hamburger bar
so we have access to use it -->
<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
</head>
<body>
<!-- Here we create our nav bar element -->
<nav>
<!-- and then give it a div to contain our icon and a class
name to use in our css to make it disappear and
reappear at will! -->
<div class="hamburger">
<!-- This is where we're sticking the icon itself -->
<i class="material-icons">menu</i>
</div>
<!-- OUTSIDE of our hamburger icon's div container, we want
to place our unordered list of links that make up our nav bar
itself, and give it a different class - this is how we'll be
able to set up our javaScript function to listen for a click
and then display the hamburger bar ONLY based on media query,
and separately display the nav bar in association with our e
vent listener, which will check for the click event happening
on the hamburger bar, and toggle our nav bar display on or
off, depending! -->
<ul class="nav-links">
<!-- our unordered list items - the links themselves -->
<li><a href="index.html">Home</a></li>
<li><a href="page2.html">About</a></li>
<li><a href="somebody@someplace.com">Contact</a></li>
</ul>
</nav>
<!-- and that's it! Then we just link to our script.js - remember,
this should go at the end of the body to ensure that no scripts
are trying to run before the element they are attached to
actually exists! 👍 -->
<script src="script.js"></script>
</body>
</html>
Great! So we have the "skeleton" of our nav bar. Let's flesh it out and make it it mobile-friendly, shall we? Enter - CSS!
.hamburger {
display: none;
}
.nav-links {
display: flex;
}
@media screen and (max-width: 768px) {
.nav-links {
display: none;
flex-direction: column;
}
.hamburger {
display: block;
}
}
It doesn't get much easier than that. Here's what we have going on in that sample style.css file:
/* First we set up our desktop view - remember,
our icon is only meant to show on mobile, so
we have set it's "display" property to have a
value of "none" by default. */
.hamburger {
display: none;
}
/* then we make sure our nav links will "flow" correctly
by setting display to "flex" */
.nav-links {
display: flex;
}
/* media query time! We're selecting anything that
has a max width of 768px - this can be anything you want,
but generally you should choose the width of the most popular
mobile devices at the time, or mobile standards, like iPhone
9 or above or Samsung S20 or above. */
@media screen and (max-width: 768px) {
/* now we set the nav links to display "none" - or dissappear
by default - every time the screen size is a mobile size. */
.nav-links {
display: none;
/* we also want to make sure they now "flex" into a column
when they do display; */
flex-direction: column;
}
/* ...and our hamburger icon now defaults to be displayed as a block
rather than display "none", as it does on desktop view */
.hamburger {
display: block;
}
}
/* The net result is that there is now a class which makes the icon display
when we're in mobile view, and a class which makes the nav bar disappear
in mobile view. */
We're almost there, believe it or not!
So now we have a desktop view that shows no hamburger icon but does show our nav links in a nice smooth row, and we have a mobile view where the hamburger icon DOES show up, and the nav links disappear instead - and if the nav links DO appear, they'll be in a column.
That just leaves the magic of change - of ACTION! Now we visit the world of JavaScript to power this magic:
var hamburger = document.querySelector('.hamburger');
var navLinks = document.querySelector('.nav-links');
hamburger.addEventListener('click', function () {
navLinks.style.display = navLinks.style.display === 'none' ? 'flex' : 'none';
});
I know. It CAN'T be that easy, right?
It really, really is.
Let's break this down:
// Because everything we're messing with is html, we need to give it a
// name, so-to-speak, over here in the world of js. We can do that by
// creating a variable to house each element we want to manipulate,
// and assigning the value as being basically, "the result of querying
// the DOM and retrieving any element matching X", where "X" is the name
// of the class or id we gave that element. Check it out:
// our hamburger icon:
var hamburger = document.querySelector('.hamburger');
// and our nav bar itself:
var navLinks = document.querySelector('.nav-links');
// now we just add an eventlistener that listens to the hamburger icon
// to receive a "click" event.
hamburger.addEventListener('click', function () {
// every eventListener is built by default to accept two parameters -
// the event that it's listening FOR, and a "callback function", or a
// function it fires off in response to "hearing" the event occur. When
// this eventListener in particular "hears" a "click" on our "hamburger"
// element, it fires off this function, which is a terniary statement.
navLinks.style.display = navLinks.style.display === 'none' ? 'flex' : 'none';
// This teriary is basically an if-else statement (like all terniearies are)
// and essentially says, "ReAssign the value of the 'display' attribute of
// navLinks' style based on the result of the following assessment:
// IF the value of the display property AT THAT TIME is currently set to
// "none", change it to be "display: 'flex'.
});
And yes - that REALLY IS IT!
By incorporating mobile optimization standards like these, you’ll unleash the power of your apps on ANY device — the possibilities for specialization from here are endless, so start simple, yes… But then go play!
The world is your responsive web-designed oyster! 😁
Top comments (1)
Thank you for this information.