Let’s build a simple, responsive navigation bar with HTML CSS and a little bit of vanilla JS.
Hello, Medium community! In my first article here I would like to share some basic skills of front-end web development by building a navigation bar that will look good on any device (desktop computer, tablet, smartphones).
What do you need?
- Basic knowledge about HTML, CSS and JavaScript
- Computer with Internet access (obviously)
- Text editor of your choice
Final code of this tutorial is uploaded on Code Pen. The link can be found on the bottom of the article.
Let’s get started!
HTML
Let’s start with writing our markup in html file:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"><link rel="stylesheet" href="./style.css"><title>LOGO</title></head><body><header><h1 class="logo">LOGO</h1><ul class="nav"><li class="navlink"><a href="#">Home</a></li><li class="navlink"><a href="#">About</a></li><li class="navlink"><a href="#">Projects</a></li><li class="navlink"><a href="#">Contact</a></li></ul><div class="burger"><i class="fas fa-bars"></i></div></header><script src="./main.js"></script></body></html>
As you can see we imported FontAwesome icons to our document, linked our .css stylesheet and our .js script. We also added some markup for our navigation bar in the <header> tag. Let’s look ho it looks so far:
CSS
Yep. As expected it looks like trash. So our next step is to add some style. In our CSS let’s format our navbar using flex CSS property:
html,body {margin: 0;padding: 0;}header {width: 100%;height: 100px;display: flex;align-items: center;justify-content: space-around;}.nav {display: flex;justify-content: space-around;width: 30%;}
.nav li {list-style: none;margin: 0;}
We used display: flex property to make our logo, navlink list and hamburger icon displayed in one line instead of one under another. align-items: center makes the child elements vertically aligned in the middle of the bar. justify-content: space-around adds space around the neighboring child elements.
If we take a look at our document now, it will look like this:
More CSS
Let’s add some more styling to it so it will look more modern:
html,body {margin: 0;padding: 0;font-family: Arial, Helvetica, sans-serif;}header {width: 100%;height: 70px;display: flex;align-items: center;justify-content: space-around;background: #232323;color: #ccc;}.logo {letter-spacing: 3px;}.nav {display: flex;justify-content: space-around;width: 30%;}.navlink {list-style: none;margin: 0;}.navlink a {color: #ccc;text-decoration: none;font-size: 1.2em;}.burger {font-size: 1.2em;display: none;}
So we modified our CSS a little bit. We used Arial, Helvetica, sans-serif as our font stack. I like to set dark backgrounds in my projects so I set #232323 which is a very dark shade of grey as background color and for contrast I used light grey (#ccc) color for my text. It’s just my preference so you may use any colors, fonts you like. I also made fonts a little bit bigger for better readability. Note that .burger item display value has been set to none. It is important. We will make this icon appear on mobile devices only. Here’s how it looks like so far:
Responsiveness
We can see that our navigation bar looks good on big displays. The problem appears when somebody will try to open our site on a mobile device. They will see something like this:
CSS media queries
Here is where CSS media queries come to action. In simple words media query is a block of CSS properties that are used only when certain conditions are true. In our case our condition will be display size. It means that different styles will be applied to our document when it’s opened on a device with smaller display (like smartphone or tablet).
At the bottom of our stylesheet let’s add following line of code:
@media screen and (max-width: 678px) {/* Styles go here */}
What it does is checking if the screen width of given device is less than 678px wide. If it is it will apply style properties from the inside of curly braces.
Now let’s stop for a second and think. What kind of behavior we need from our navigation when opened on such a small device. First of all we would like our hamburger icon to appear instead of navigation links. We will also want the navigation links to be hidden by default and to appear only after tapping the hamburger icon (we will get to it later writing our .js).
Inside of our media query let’s add some style:
@media screen and (max-width: 678px) {.burger {display: block;}.nav {margin: 0;background: #343434;position: absolute;right: 0;top: 70px;width: 50%;height: calc(100% - 70px);flex-direction: column;justify-content: space-around;padding: 0;}.navlink {text-align: center;}}
Aside from styling with text and background color there are way more important things. The burger icon is now visible by setting .burger’s display value to block. We set navigation menu’s position to absolute which means we can position this item wherever we like based on right and top properties. In this case it’s set to appear on the right side of the window. We set flex-direction to column so the menu items will appear one under another instead of one line. The height property is also worth attention. It’s set to calc() value. It sets the height of our side menu to the difference of height of the window and height of the navigation bar (which was set to 70px). Let’s have a look on it now:
W still need our navigation menu to be hidden by default so let’s set .nav’s right value to -100%. It will move entire thing to the right by the 100% of it’s width so it will be hidden behind the right border of the window.
JavaScript interactivity
So we are almost there. Now we need to add interactivity to our navigation. What I mean is to trigger an action after en event occurs. In our case we want to make our side menu appear after clicking on the burger icon on the top right. We will also make the icon change to an X icon that will make the menu disappear. Before jumping to JavaScript let’s create yet another class inside of our media query in the .css file:
.nav-active {right: 0;}
This class is not given to any HTML object yet. It will be added and removed with JS code in order to make side menu appear on the right side and disappear right behind it. Entire JavaScript code that operates this functionality is quite short and takes just a couple lines:
// Selection of HTML objectsconst burger = document.querySelector('.burger i');const nav = document.querySelector('.nav');// Defining a functionfunction toggleNav() {burger.classList.toggle('fa-bars');burger.classList.toggle('fa-times');nav.classList.toggle('nav-active');}// Calling the function after click event occursburger.addEventListener('click', function() {toggleNav();});
Firstly, proper HTML objects are selected with .querySelector method. Personally it’s my favorite methond for selecting DOM objects. It allows to select items almost the same way as CSS.
Then we declare a function toggleNav() which swithces between fa-bars and fa-times class. These classes are FontAwesome classes that represent icons we need. In effect it will change the burger icon to an x icon and back. And most importantly it till add and remove nav-active class which in effect will show and hide our side menu.
Lastly we add an event listener to the icon that in our case is clicking it. It will call the previously declared toggleNav function everytime the icon is clicked.
Final touch
So far we managed to write markup, styles and JS code to cover basic functionality of our responsive navbar. My recommendation is to add some visual effects to it. For instance make the side navigation slide in smoothly by adding transition property to the nav class.
.nav {
...transition: all 400ms;
...
}
Aaaand that would be it for a simple responsive navigation bar.
There are plenty of things you may want to add/change/remove/do it our way. If you have such an idea please share it.
I’ve uploaded project’s code on Code Pen so you can have a look on it, experiment, change stuff to check if it works :)
As I mentioned before this is my very first article here on Medium. Any feedback and opinion is very welcome so I may improve next time.
Until then, happy coding :)
Adam