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

How to create a sticky navbar with CSS & JavaScript

michaelburrows profile image Michael Burrows Originally published at michaelburrows.xyz ・2 min read

[ 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">
    <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>      
  <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 -->

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;

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) {    
  } else {

window.addEventListener('scroll', fixedNav);

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;

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.

Posted on by:

michaelburrows profile

Michael Burrows


Web Developer @ michaelburrows.xyz


markdown guide

Also, you can use position: sticky;


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


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


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!