Implementing Sticky Navigation Using Javascript’s Intersection Observer API.

Implementing Sticky Navigation Using Javascript’s Intersection Observer API.

A Beginner’s Approach to the Intersection Observer API

You must have visited websites whose navigation becomes fixed on scrolling down to other pages, making it possible to navigate the website. If you observed, most of them have no background on the homepage but automatically get one or some slight changes that make their content visually appealing on other sections of the website. I trust you love this glossy feature seen on modern websites and cannot wait to implement one on your future projects. Well, if you have such thought, then you are definitely in the right place as this article will hold you by your hands and guide you through the entire process of implementing one on a simple demo website we will build from scratch. It further explains the meaning and importance of sticky navigation and how to implement it using the Intersection Observer API in Javascript. Let’s get started!

Prerequisites

  • Basic knowledge of HTML5/CSS3.

  • A basic knowledge of Javascript.

  • An updated web browser (preferably Chrome) to ensure it supports all new javascript features.

  • A text editor. Preferably visual studio code.

What is Sticky Navigation?

Sticky navigations are navigations on websites that remain fixed (in the same position) as the user scrolls to other sections of the same websites. It has become a standard on modern websites.

Sometimes, it becomes a challenge to make the navigation links visible on a section of the page that makes them less visible. Take a look at the screenshots of our demo web pages below.

The first image is our homepage with the navigation elements in white color as visibly displayed. However, they become invisible on scrolling to the next section (second image) with a white background. We can overcome this challenge by adding a background to the navigation element on other sections of the website. And this background should not contradict the visibility of the navigation elements.

Why is sticky navigation important in web design?

The primary function of sticky navigation is to enable users to navigate between web pages. Imagine visiting a website with considerably longer pages and each time you wish to divert to another part of the website, you will have to scroll to the home page to access the nav links. Trust me, you will feel exhausted and might be triggered to leave the site. But with the navigation menu always displayed, you can quickly get your content comfortably without getting lost or tired.

What is the Intersection Observer API?

You might wonder what a web API is. Well, web API is an acronym that stands for Application Programming Interface. It enables developers to quickly and easily perform complex functionalities. They provide easier syntaxes to use while getting rid of more complex codes. A good example is the Document Object Model (DOM) API which lets us pick and manipulate elements loaded in the browser.

The intersection Observer API enables us to asynchronously monitor the changes made when a target element intersects (crosses) with a root element and then triggers a callback function when this intersection occurs. Sounds confusing? Let’s simplify these terms.

The root element is a container to another element(s). In most cases, it is the browser viewport (visible area of the screen). For instance, in the markup code shown below.

<!DOCTYPE html>
   <html lang="en">
        <head>
           <title>Document</title>
        </head>
        <body>
              <p>Welcome to my world!</p>
       </body>
    </html>

The html element is the parent to other elements. The head element is parent to the title just as the body is to the p element.

On the other hand, the target element is the element we monitor to intersect the browser’s viewport or an ancestral element. It is also called the observed element.

A callback function is one passed as an argument to a higher one. It denotes the action we want to execute each time our target element intersects with the viewport. Let's see a practical demonstration of a call-back function.

const callBackFunction = function(){
    console.log('Let's call the function');
}
headerEl.addEventListener('click', callBackFunction);

The callBackFunction has been declared but passed as an argument to the addEventListener() method. It will be called each time a click event occurs on the headerEl.

I have prepared a diagram to help visualize this concept better.

Building our simple HTML/CSS page

Now that you fully understand what sticky navigation and the Intersection Observer API mean, let’s build our demo web page. For this project, we will only need three simple pages; the home page (header) and two identical sections. The header section will be our target element. Let's now code together.

Below is our complete HTML file.

<!DOCTYPE html>
<html lang="en">
 <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Sticky Nav</title>
    <link rel="stylesheet" href="style.css" />
</head>
<body>
    <header class="header">
         <nav class="header__nav">
            <h2 class="logo">MY LOGO</h2>
            <div class="nav__links">
              <a href="#" class="nav__link">Home</a>
              <a href="#" class="nav__link">About</a>
              <a href="#" class="nav__link">Pricing</a>
              <a href="#" class="nav__link">Reviews</a>
            </div>
          </nav>  
           <div class="header__contents">
              <h2> Implementing sticky navigation with Javascript Intersection Observer API</h2>
           </div>
    </header>
    <div class="section">
      <h2>A beginner's approach to Implementing sticky navigation</h2>
    </div>
    <div class="section">
      <h2>A beginner's approach to Implementing sticky navigation</h2>
    </div>
   <script src="script.js"></script>
  </body>
</html>

Having done our markup, let's see how it appears on our browser. Simply open the markup (HTML) file on your browser or use a live server extension installed on your text editor.

The markup should appear on our browser as shown below;

Now let’s style our pages to make them presentable using CSS. The complete codes are shown below;

* {
    padding: 0;
    margin: 0;
    font-family: "poppins";
  }

html {
    font-size: 62.5%;
  }
  .header {
    position: relative;
    min-height: 100vh;
    background-image: linear-gradient(to top right, #444399, #3b054b);
    color: white;
    font-weight: 300;
  }
  nav {
    display: flex;
    justify-content: space-around;
    align-items: center;
    padding: 1rem;
    font-size: 1.6rem;
  }
 .nav__link {
    color: white;
    text-decoration: none;
    margin-right: 2rem;
    font-size: 1.4rem;
  }
  .header__contents {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
  }
  .section {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  h2 {
    font-size: 3rem;
    max-width: 25ch;
    text-align: center;
  }
  .logo {
    color: white;
    font-size: 1.8rem;
  }
  .sticky {
    background: #3b054b;
    width: 100%;
    position: fixed;
  }

Wolla! Our web pages are completely set up as seen below👇

Note that we have created a sticky class in our CSS file. We will dynamically add and remove it from the navigation element when an intersection occurs. Its function is to give the navigation a background that will improve the readability of its content in other sections.

With all these in mind, let’s implement the Intersection Observer API. But before then, let’s select the elements using Javascript.

//selecting the elements
 const headerEl = document.querySelector(".header");
 const navEl = document.querySelector(".header__nav");

Here, we simply picked the HTML elements by their classes using the querySelector() method available on the document object and then store them in variables. Variables are like containers used to store values that will be used later in the program.

To select classes, we add a dot before the class name or a hash(#) symbol if an id attribute is used. Note that:

  • The headerEl variable stores the header section of our page which is the homepage.

  • The navEl variable stores the navigation element.

Implementing the Observer API

This API is created by calling its constructor as shown below.

 const headerObserver = new IntersectionObserver(stickyNav, option);

It accepts two arguments; a call-back function and an option object(optional).

For our work, we named the constructor as headerObserver and the function as stickyNav. Can you still recall what a callback function is? It is a function passed as an argument to another one and is triggered when an event occurs.

The option object enables us to customize(change) the conditions under which the callback function is called. It is optional (can be omitted) in which case the default fields are used. These fields include the following:

root

It is the ancestral (parent) element to the target element. By default, its value is set to null. It implies that our target element should monitor the browser’s viewport (screen).

rootMargin

The root element is seen as a rectangular frame with four sides. The rootMargin adds positive or negative margins on the root element to respectively grow or shrink its sides before the intersection occurs. Its value is given in pixels (px) or percentages (%) enclosed in quotes. By default, it is set to zero.

threshold

It is a single value or array of values which denotes the percentage of our target’s visibility before the callback function is executed. It can only take a value between 0 and 1. A value of 0.1 means the target element should be visible by 10% before the function is called. The default value is zero, indicating the callback should run as soon as the observed (target) element hits 0px of the parent element.

After creating the constructor, we need to give it a target element to monitor. It is done using its built-in observe() method. Our target element is the header element which was stored in the headerEl variable.

 headerObserver.observe(headerEl);

Creating the option object

It is time to create our option object. We will keep it simple by using the default values, meaning we can ignore the option argument. However, to see how it is defined, let’s include it.

Note that objects are not hoisted. Thus, cannot be used before they are declared. Therefore, it must be declared before calling the observer constructor.

const option = {
    root: null,
    threshold: 0,
    rootMargin: "0px",
  };

The null value simply sets the root element to the browser’s viewport. A threshold of 0 means the callback will be called as soon as the target element hits 0% of the root element. Finally, the rootMargin of 0 indicates that we neither want the root to grow nor shrink.

To this end, the only thing left is to declare the callback function. So let’s do that right away.

Creating the Callback Function

It is worth knowing that any web page with the intersection Observer API will always trigger the callback function on its initial load. The callback then receives an array containing the intersectionObserverEntry object from the Observer. Sounds confusing? Enough of the chit-chat as we declare the function right away.

 const stickyNav = function (entries) {
    console.log(entries)
  };

The entries are passed as an argument to the function. With the web page loaded on your browser, hit F12 to open the dev tools. Click on the console to see these entries.

As shown above, you can see a series of details concerning the intersection. We won’t explain everything. The only one that is of concern to us is the isIntersecting property. It gives a boolean true value if the target is currently intersecting with the root at the specified threshold or a false value if it is not. For our work, we have a value of true. I believe you can figure out the reason. Well, our target element (header) is currently visible on the viewport. Therefore, it is intersecting.

To further experiment with these values, scroll down the page and notice that the value changes to false. We can therefore use this to our advantage by simply implementing the logic of adding the sticky class defined in our CSS to the navEL element when the isIntersecting value is false (not intersecting) and removing it when it is true (intersecting). So let’s do that.

const stickyNav = function (entries) {
  console.log(entries);
  const [entry] = entries; //extracting the intersectionObserverEntry object
  if (!entry.isIntersecting) navEl.classList.add("sticky");
  else {
    navEl.classList.remove("sticky");
  }
};

And boom, that solves the last bit of the puzzle. Scroll down the page and see that the navigation element takes the properties defined in the sticky class. Also, the sticky class is removed when scrolling up to the homepage again. It is amazing, right? I believe you are impressed😊. You can see the changes in the other section below.

And here is a summary of our javascript codes.

//selecting the elements
const headerEl = document.querySelector(".header");
const navEl = document.querySelector(".header__nav");
const sectionEl = document.querySelector(".section");

//callback function
const stickyNav = function (entries) {
  console.log(entries);
  const [entry] = entries;
  if (!entry.isIntersecting) navEl.classList.add("sticky");
  else {
    navEl.classList.remove("sticky");
  }
};

//options object
const options = {
  root: null,
  threshold: 0,
  rootMargin: "0px",
};
const headerObserver = new IntersectionObserver(stickyNav, options);
headerObserver.observe(headerEl);

Wrapping Up!

Congratulations on making it to the end of this article! It was quite a long but intriguing session. I am glad you successfully implemented sticky navigation on a demo website and as well understood how Javascript’s Intersection Observer API works and how to use it. It is a vital skill to add to your coding arsenal. As you may know, there are lots of other exciting features you can implement on your websites using this API. You can make features like lazy-loading of images on page scroll, revealing contents smoothly, and more. I will drop articles on them. Endeavor to stay in touch.

If you find this article interesting (which I believe you do), kindly support me by liking this article and also follow me to see more exciting articles. For reactions to errors in the article, drop them in the comment section. We can discuss them together.

Are you aspiring to become a front-end developer? I have an article that can get you started. You can check it out on Basics of front-end development

For in-depth learning of the Observer API, check out Mdn.