Responsive Navigation Bar Tutorial | HTML & CSS
Tags: html, css, webdev, codenewbie
Published: 2021-06-28 08:05:07

Hello friends,

In this post I will show you how you can create an awesome responsive navbar using just `HTML` and `CSS`. We will also add some cool *hover effect* on our links.

>This tutorial needs you to have a basic understanding of HTML and CSS.

*The following is a sneak pick of what we will be creating*
- You can preview the live version here: [Responsive Nav](https://chaoocharles.github.io/responsive-navbar-html-css/)
- You can get the entire source code here: [Source code](https://github.com/chaoocharles/responsive-navbar-html-css)

![Side Nav Preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2mzghd2gsgvfb229wgp.PNG)

###Video Tutorial
If you prefer a step by step *video tutorial*, I got you sorted. For those who prefer to *read*, you can continue below. 

>You can support my channel by just subscribing. Please get me to 5k subscribers. 🤗

{% youtube Camwh6hk4wY %}

##Desktop Navbar
Let's start by creating the following desktop nav.
![Desktop Nav](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54lqgd59gbcigquhchff.PNG)

As you can see from above, we have the logo on the left and the links on the right. We are also dividing the links into two, the overview links and account links. We will organize our code in the same manner as shown below. 
###Step 1: HTML Markup
```html
<!DOCTYPE html>
<html>
  <head>
    <title>Nav Bar</title>
  </head>
  <body>
    <nav>
      <div class="logo">
        <h2>NavBar</h2>
      </div>
      <div class="nav-items">
        <ul class="overview">
          <li><a href="#">Home</a></li>
          <li><a href="#">Dashboard</a></li>
          <li><a href="#">Rates</a></li>
          <li><a href="#">Contact</a></li>
        </ul>
        <ul class="account">
          <li><a href="#">Notifications</a></li>
          <li><a href="#">Settings</a></li>
        </ul>
      </div>
    </nav>
    <div class="hero-section"></div>
  </body>
</html>
```

From the code above, we added a `nav` tag inside the `body`. Inside the nav tag we added two `div` tags. One will hold our *logo* and the other one will hold our *nav items*.  Inside the nav items, we used two `ul` elements to divide our links into overview links and account links. We then added `a` tags for our links inside the `li`. It is important to note how the code is organized because it will be useful when we layout our nav using `css flexbox`. 

After the `nav` we are also adding a `div` with a class of *hero-section*. We will use it to add the background image. 

![Image preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5pnjgnibef1lg7rl1zhr.PNG)

Let's link our HTML file to our CSS file by adding a `link` tag at our `head` as shown below.

```html
<head>
    <meta charset="utf-8" />
    <title>Nav Bar</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" type="text/css" media="screen" href="main.css" />
  </head>
```

From above, we are also adding 2 `meta` tags. The first meta tag will tell the browser to use **UTF-8 character encoding** which is a method of converting your typed character code into machine readable code. The second meta tag helps in controlling layout in mobile browsers. The `width` property controls the size of the viewport. The `initial-scale` controls the zoom level when the page first loads. This will come into play when making our navbar to be mobile responsive.
###Step 2: The CSS

```css
@import url("https://fonts.googleapis.com/css2?family=Rubik&display=swap");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Rubik", sans-serif;
}
```
From above we are importing `Rubik` font from google fonts. Be free to use any font that you want. We are then clearing the defaults by setting the `margin` and `padding` for all elements to 0. Setting the `box-sizing` property as `border-box` allows us to include the padding and border in an element's total width and height.

Let's style our `nav` below:
```css
/* Hero section */
.hero-section {
  height: 100vh;
  background: url("hero-bg.jpg") center no-repeat;
  background-size: cover;
}
/* Nav */
nav {
  height: 70px;
  background: rgb(20, 20, 20);
  color: rgb(220, 220, 220);
  padding: 0 2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: sticky;
  top: 0;
}
```
The most important thing to note from above is the `display: flex` at our nav. This will make the `nav` element to be a flex container and by default the `flex direction` will be `row`. This will make our logo and nav-items to be side by side. We then push them apart by using `justify-content: space-between`. Adding `position: sticky` and `top:0` will make our nav to remain at the top even after scroll.

![Image preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7bqnun6kdom14ob9t1m.PNG)

Our links are still aligned `vertically`. To arrange them in a `horizontal` manner, lets add the following stylings.
```css
.nav-items,
.overview,
.account {
  display: flex;
}
.overview {
  margin-right: 4rem;
}
```
Adding a display of flex to the `nav-items` will place the `overview` section and the `account` section side by side. We then place all the `li` items to be side by side by adding a display of flex to the `overview` and `account`. Adding a `margin-right` to the `overview` will simply create some spacing between our overview and account.

![Image preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2xxc3q8igz2cxo6t50z.PNG)

At this point our links are nicely organized but they don't look pretty. Let's make them pretty 🎨 plus add some cool `hover` effect
```css
.logo h2 {
  text-decoration: overline;
  font-style: italic;
  color: rgb(0, 206, 206);
  cursor: pointer;
  margin: 0 0.5rem;
}
nav li {
  list-style: none;
  margin: 0 0.5rem;
}
nav a {
  text-decoration: none;
  color: rgb(220, 220, 220);
}
nav a:hover {
  color: #a0ebfd;
}
nav a::after {
  content: "";
  display: block;
  height: 3px;
  background: #a0ebfd;
  width: 0%;
  transition: all ease-in-out 300ms;
}
nav a:hover::after {
  width: 100%;
}
```
Above we are simply removing the `list-style` and `text-decoration`. We are then changing the color for our links and changing it again on `hover`. We are also creating some spacing between our links using `margin: 0 0.5rem` at our `li`.

What I think I should explain in details is the weird syntax `::after`. This is called an *after pseudo selector*. It can enable us to add some content after any html element. What we want to do in this case is to add some `underline hover effect`. We will create a line under our links by adding a display of block to `a::after`. This will allow us to give it a height of `3px` (you are free to change this value) and a `color`.

We then create the underline effect by setting the width of our line as `0%` and transition it to `100%` on hover. At this point our desktop nav is complete and it has the nice hover effect.

![Image preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnpkvtlpkum6fd5udqeg.PNG)

##Side Navbar
Now it's about time we work on our side navbar. Take a look at the following image. We want something like this.
![Side Nav Preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2mzghd2gsgvfb229wgp.PNG)
From above, you can see that there is a lot more going on. Our links now have icons and sections have headings. We also have a menu icon to show/hide our side navbar. We therefore need to edit our HTML file and add all the necessary markup.
###Step 3: Edit HTML
This will be our complete HTML markup for both the desktop navbar and side navbar.
```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Nav Bar</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" type="text/css" media="screen" href="main.css" />
  </head>
  <body>
    <nav>
      <input type="checkbox" id="check" />
      <label for="check" class="menu">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="30"
          height="30"
          fill="currentColor"
          class="bi bi-list"
          viewBox="0 0 16 16"
        >
          <path
            fill-rule="evenodd"
            d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"
          />
        </svg>
      </label>
      <div class="logo">
        <h2>NavBar</h2>
      </div>
      <div class="nav-items">
        <ul class="overview">
          <h3>Overview</h3>
          <li>
            <a href="#"
              ><svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                fill="currentColor"
                class="bi bi-house-fill"
                viewBox="0 0 16 16"
              >
                <path
                  fill-rule="evenodd"
                  d="m8 3.293 6 6V13.5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5V9.293l6-6zm5-.793V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"
                />
                <path
                  fill-rule="evenodd"
                  d="M7.293 1.5a1 1 0 0 1 1.414 0l6.647 6.646a.5.5 0 0 1-.708.708L8 2.207 1.354 8.854a.5.5 0 1 1-.708-.708L7.293 1.5z"
                />
              </svg>
              Home</a
            >
          </li>
          <li>
            <a href="#">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                fill="currentColor"
                class="bi bi-speedometer"
                viewBox="0 0 16 16"
              >
                <path
                  d="M8 2a.5.5 0 0 1 .5.5V4a.5.5 0 0 1-1 0V2.5A.5.5 0 0 1 8 2zM3.732 3.732a.5.5 0 0 1 .707 0l.915.914a.5.5 0 1 1-.708.708l-.914-.915a.5.5 0 0 1 0-.707zM2 8a.5.5 0 0 1 .5-.5h1.586a.5.5 0 0 1 0 1H2.5A.5.5 0 0 1 2 8zm9.5 0a.5.5 0 0 1 .5-.5h1.5a.5.5 0 0 1 0 1H12a.5.5 0 0 1-.5-.5zm.754-4.246a.389.389 0 0 0-.527-.02L7.547 7.31A.91.91 0 1 0 8.85 8.569l3.434-4.297a.389.389 0 0 0-.029-.518z"
                />
                <path
                  fill-rule="evenodd"
                  d="M6.664 15.889A8 8 0 1 1 9.336.11a8 8 0 0 1-2.672 15.78zm-4.665-4.283A11.945 11.945 0 0 1 8 10c2.186 0 4.236.585 6.001 1.606a7 7 0 1 0-12.002 0z"
                />
              </svg>
              Dashboard</a
            >
          </li>
          <li>
            <a href="#"
              ><svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                fill="currentColor"
                class="bi bi-bar-chart-fill"
                viewBox="0 0 16 16"
              >
                <path
                  d="M1 11a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-3zm5-4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7zm5-5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V2z"
                />
              </svg>
              Rates</a
            >
          </li>
          <li>
            <a href="#"
              ><svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                fill="currentColor"
                class="bi bi-envelope-fill"
                viewBox="0 0 16 16"
              >
                <path
                  d="M.05 3.555A2 2 0 0 1 2 2h12a2 2 0 0 1 1.95 1.555L8 8.414.05 3.555zM0 4.697v7.104l5.803-3.558L0 4.697zM6.761 8.83l-6.57 4.027A2 2 0 0 0 2 14h12a2 2 0 0 0 1.808-1.144l-6.57-4.027L8 9.586l-1.239-.757zm3.436-.586L16 11.801V4.697l-5.803 3.546z"
                />
              </svg>
              Contact</a
            >
          </li>
        </ul>
        <ul class="account">
          <h3>Account</h3>
          <li>
            <a href="#"
              ><svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                fill="currentColor"
                class="bi bi-bell-fill"
                viewBox="0 0 16 16"
              >
                <path
                  d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2zm.995-14.901a1 1 0 1 0-1.99 0A5.002 5.002 0 0 0 3 6c0 1.098-.5 6-2 7h14c-1.5-1-2-5.902-2-7 0-2.42-1.72-4.44-4.005-4.901z"
                />
              </svg>
              Notifications</a
            >
          </li>
          <li>
            <a href="#"
              ><svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                fill="currentColor"
                class="bi bi-gear-fill"
                viewBox="0 0 16 16"
              >
                <path
                  d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"
                />
              </svg>
              Settings</a
            >
          </li>
        </ul>
      </div>
    </nav>
    <div class="hero-section"></div>
  </body>
</html>
```
Now, the above code looks so messed up because of the `svg` icons. But don't worry, I will try to break everything down for you. The first thing we are adding is a `checkbox` just after the opening nav tag. We then add a `label` for this checkbox. The label holds the **svg menu icon**. 

>I got the svg icons from https://icons.getbootstrap.com/

From below, note how the `id` of the checkbox is similar to the `for attribute` of the label. This links our label to our checkbox such that when we click on the label, it should check and uncheck the check box. This is what will help us to `show` and `hide` the side navbar depending on whether the checkbox is checked or not. I also manually manipulated the width and height of our svg to `30`
```html
      <input type="checkbox" id="check" />
      <label for="check" class="menu">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="30"
          height="30"
          fill="currentColor"
          class="bi bi-list"
          viewBox="0 0 16 16"
        >
          <path
            fill-rule="evenodd"
            d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"
          />
        </svg>
      </label>
```
The next thing we added is some headings for our overview and the account sections. They will make our side navbar to look more organized. Lastly we added svg icons inside our `a` tags just before the text. Note how there is a spacing between the icons and the text.
###Step 4: Edit CSS
If you preview what we have on the browser, you will see that our desktop navbar is now messed up. It has unnecessary headings and icons. 

![image preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tc2f0n98crxht2odvla4.PNG)

**We can hide all the svg's, headings and checkbox with the following code in our CSS.**
```css
nav svg, .nav-items h3, #check, .menu {
  display: none;
}
```
Let's style the side navbar
```css
/* Responsive */
@media (max-width: 750px) {
  .nav-items {
    position: fixed;
    top: 0;
    right: -250px;
    height: 100vh;
    width: 250px;
    flex-direction: column;
    justify-content: space-evenly;
    background: rgb(20, 20, 20);
    padding: 2rem;
    transition: all ease-in-out 500ms;
  }
  .overview,
  .account {
    flex-direction: column;
    width: auto;
  }
  .overview {
    margin: 0;
  }
  .nav-items h3 {
    display: inline-block;
    font-weight: 400;
    text-transform: uppercase;
    font-size: 13px;
    margin-bottom: 1rem;
  }
}
```
Above we a setting a break point for screen sizes using `@media (max-width: 750px)`. This code is what helps us differentiate between the mobile version and the desktop version. It is called **CSS Media Queries**. When we have a screen with a width of 750px or less, the code inside the @media block will be applied, else the code will be ignored.

We are then selecting the `nav-items` and adding stylings to make it our `side navbar` when we are at a screen size of 750px or less. We are changing the direction of our flex items by using the `flex-direction` property. Note how the `right` property is set to `-254px`. By default we want side navbar to be hidden. When the checkbox is checked we will move the `side navbar` from `-254px` to `0px`. 

>This preview is when `right` is set to `0px`

![Image preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmhl1lxjbf5znueimumh.PNG)

The following code is the last piece of the puzzle.
```css
nav svg {
    display: inline-block;
    cursor: pointer;
    vertical-align: top;
  }
  nav li {
    margin: 1rem 0;
  }
  nav a {
    display: inline-block;
  }
  nav a:hover {
    margin-left: 2px;
    transition: all ease-in-out 300ms;
  }
  .menu {
    display: inline-block;
    position: fixed;
    right: 2.5rem;
    z-index: 99;
  }
  #check:checked ~ .nav-items {
    right: 0;
  }
```
This character `~` is called `tilde`. In CSS it is called `the general sibling combinator`. It will help us select the `.nav-items` which is a sibling of our checkbox. We select the nav-items only when the checkbox is checked and set the `right` property to `0`. This will make our side navbar to be visible.

>Test the complete version here: [Responsive Nav](https://chaoocharles.github.io/responsive-navbar-html-css/)

From above there are other stylings to make our icons, links and menu visible and organized. I didn't cover them because I think they are self explanatory. If you don't understand you can check out the video I pinned at the very top for a more detailed explanation.

**Our final CSS file will look like the following:**
```css
@import url("https://fonts.googleapis.com/css2?family=Rubik&display=swap");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Rubik", sans-serif;
}

/* Nav */
nav {
  height: 70px;
  background: rgb(20, 20, 20);
  color: rgb(220, 220, 220);
  padding: 0 2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: sticky;
  top: 0;
}
nav svg {
  display: none;
}
.logo h2 {
  text-decoration: overline;
  font-style: italic;
  color: rgb(0, 206, 206);
  cursor: pointer;
  margin: 0 0.5rem;
}
.nav-items {
  display: flex;
  justify-content: space-between;
}
.overview,
.account {
  display: flex;
}
.overview {
  margin-right: 4rem;
}
.nav-items h3 {
  display: none;
}
nav li {
  list-style: none;
  margin: 0 0.5rem;
}
nav a {
  text-decoration: none;
  color: rgb(220, 220, 220);
}
nav a:hover {
  color: #a0ebfd;
}
nav a::after {
  content: "";
  display: block;
  height: 3px;
  background: #a0ebfd;
  width: 0%;
  transition: all ease-in-out 300ms;
}
nav a:hover::after {
  width: 100%;
}
#check,
.menu {
  display: none;
}

/* Hero section */
.hero-section {
  height: 100vh;
  background: url("hero-bg.jpg") center no-repeat;
  background-size: cover;
}

/* Responsive */
@media (max-width: 750px) {
  .nav-items {
    position: fixed;
    top: 0;
    right: 0;
    height: 100vh;
    width: 250px;
    flex-direction: column;
    justify-content: space-evenly;
    background: rgb(20, 20, 20);
    padding: 2rem;
    transition: all ease-in-out 500ms;
  }
  .overview,
  .account {
    flex-direction: column;
    width: auto;
  }
  .overview {
    margin: 0;
  }
  .nav-items h3 {
    display: inline-block;
    font-weight: 400;
    text-transform: uppercase;
    font-size: 13px;
    margin-bottom: 1rem;
  }
  nav svg {
    display: inline-block;
    cursor: pointer;
    vertical-align: top;
  }
  nav li {
    margin: 1rem 0;
  }
  nav a {
    display: inline-block;
  }
  nav a:hover {
    margin-left: 2px;
    transition: all ease-in-out 300ms;
  }
  .menu {
    display: inline-block;
    position: fixed;
    right: 2.5rem;
    z-index: 99;
  }
  #check:checked ~ .nav-items {
    right: 0;
  }
}
```

Now you can try this navbar on your website.

>This is my first time writing such an article. Let me know how I did at the comment section below 😊. Do you want more from me?

>I'm on twitter: https://twitter.com/ChaooCharles
and Youtube: https://www.youtube.com/c/chaoocharles

Always stay awesome 💙