DEV Community

Cover image for How to create a sticky navbar with CSS & JavaScript
Michael Burrows
Michael Burrows

Posted on • Edited on • Originally published at w3collective.com

How to create a sticky navbar with CSS & JavaScript

[ CodePen Demo | Original Article ]

Sticky navbar’s allow users to access a website’s navigation even when they’ve scrolled down the page.

In this example we’ll be creating a sticky navbar that also shrinks in size when the nav becomes fixed.

Let’s get started by creating the HTML:

<header id="header"></header>
<nav id="nav">
  <ul>
    <li><a href="#"><img src="https://img.icons8.com/color/96/000000/javascript.png" height="96" /></a></li>
    <li><a href="#">Documentation</a></li>
    <li><a href="#">Tutorials</a></li>
    <li><a href="#">Blog</a></li>
    <li><a href="#">Community</a></li>      
  </ul>
<article> 
  <h1>Lorem Ipsum Dolor</h1>
  <p>Consectetur adipiscing elit. Praesent vulputate elit felis, quis efficitur tortor viverra a. Quisque fermentum enim et enim imperdiet vestibulum at vitae tortor. Cras auctor scelerisque odio at varius. Nullam rhoncus nibh ut sem dignissim fringilla. Fusce dapibus nulla sed ipsum commodo molestie ut ut mauris.</p>  
  <!-- repeat as required -->
</article>
</nav>
Enter fullscreen mode Exit fullscreen mode

Next for the CSS:

#header {
  height: 30vh;
  background: url(https://images.pexels.com/photos/1089440/pexels-photo-1089440.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940);
  background-size: cover;
}
#nav {
  background-color: #000;
  top: 0;
  width: 100%;
}
#nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
}
#nav li {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}
#nav ul li a {
  color: #ffd600;
  transition: all 0.4s;
}
#nav ul li img {
  height: 96px;
  transition: height 0.4s;
}
Enter fullscreen mode Exit fullscreen mode

This create's a header image and full width navbar with each of the <li> elements disturbed evenly apart.

Now for the JS that detects when the navbav has reached the top of the browser and adds a fixed class:

const nav = document.querySelector('#nav');
let navTop = nav.offsetTop;

function fixedNav() {
  if (window.scrollY >= navTop) {    
    nav.classList.add('fixed');
  } else {
    nav.classList.remove('fixed');    
  }
}

window.addEventListener('scroll', fixedNav);
Enter fullscreen mode Exit fullscreen mode

Finally the CSS for when the navbar has the fixed class activated:

#nav.fixed {
  position: fixed;
  box-shadow: 5px 5px 19px 0px rgba(0, 0, 0, 0.5);
}
#nav.fixed ul li img {
  height: 36px;
}
#nav.fixed ul li a {
  font-size: 14px;
}
Enter fullscreen mode Exit fullscreen mode

As we have transitions on the <img> and <a> elements when the fixed class is applied they’ll scale smoothly.

This is however is optional as you could just add the fixed positioning for a sticky navbar without any scaling.

Top comments (4)

Collapse
 
jjmato profile image
Juan

Also, you can use position: sticky;

Collapse
 
devbyrayray profile image
Dev By RayRay

This would also be my choice 😉 It's made for this situation 👍

Collapse
 
michaelburrows profile image
Michael Burrows

Ahh yess, I had it in my mind that this wasn't well supported yet but indeed it is.

Collapse
 
thomasledoux1 profile image
Thomas Ledoux

Nice implementation!
For the Javascript part, you might want to consider using Intersection Observer (developer.mozilla.org/en-US/docs/W...) to track if the menu is in the viewport or not. It's highly configurable, you can even set thresholds too!