DEV Community

Bekka
Bekka

Posted on • Edited on

How to observe your web page for scrolls with little calculations

Hi people, it's been over a year since I posted my first blog post. I was going through a lot of personal issues, so I had to take a long break from social media. I'm here now, thank God. Hopefully,this post helps you (the person reading this). Alright, back to the main topic of this post.

A lot of devs struggle with observing the web page on scrolls and stuff. There are solutions, either by calculating the offset of the element or some other solution.

Prerequisities

you need to know HTML, CSS and JS. I'm not going to over that in this post.

If you already know HTML, CSS and JS, you can continue reading this post.

The Intersection Observer API

According to mdn's definition, "The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's view port".

Many years ago, web developers had to do lots of calculations on observing the page's view port using tools like offset and the likes, which could get messy, as the user's experience starts to be unpleasant. The intersection Observer API can be used for the following:

  • Lazy-loading images or page content
  • CSS animations
  • Infinite scrolling

It can basically be used for observing the elements in the page or when the elements will be in view. Which can be handy because you don't really need much calculations, you just need the Intersection observer!.

To demonstrate how to use the Intersection Observer API, We are going to build a simple web page with contents to observe and then we make our page react when elements are in view and also when they are not.

Alright, let's write some code!

Firstly, Create a folder named intersection-observe or any name you like. In this directory, create a HTML file, a CSS file and a JS file.

Like I said earlier, I'm not going to go over the tags and stuff, I assume you already have knowledge of that.

Next, Copy the following code below to the html file, We are just going to display a list of post, with a navbar.

<!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>Intersection Observer!</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div class="main--container">
      <div class="nav--wrapper">
        <nav class="navbar--container nav-intersect">
          <ul class="links--container">
            <li class="navlink logo">Logo</li>
            <li class="navlink">Home</li>
            <li class="navlink">About</li>
            <li class="navlink">Contact</li>
          </ul>
        </nav>
      </div>
      <div class="posts--container">
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
        <div class="card">
          <div class="card-title">Card title</div>
          <div class="card-body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Similique
            laudantium assumenda soluta unde tenetur impedit possimus, iure
            nobis illum eaque? Consequuntur nisi modi nesciunt vero placeat sit,
            reiciendis ratione deleniti.
          </div>
        </div>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode

Make sure you replace the style and script file names to your the custom names you created, so that you can see the changes.

Currently the page will look like this:-
Image description

Then go to your css file and copy the following code into it.

* {
  margin: 0;
  padding: 0;
}

.navbar--container {
  height: 7vh;
  background-color: white;

  position: fixed;
  width: 100%;
}

.nav--wrapper {
  height: 7.5vh;
  width: 100%;
}

.nav-intersect {
  position: fixed;
  z-index: 10;
  /* -webkit-box-shadow: 0px 1px 3px -1px rgba(105, 105, 105, 0.79);
  -moz-box-shadow: 0px 1px 3px -1px rgba(105, 105, 105, 0.79); */
  box-shadow: 0px 1px 3px -1px rgba(105, 105, 105, 0.79);
}

.links--container {
  padding-top: 20px;
  display: flex;
  list-style: none;
}

li:nth-child(2) {
  margin-left: auto;
}

.navlink {
  padding: 0 5px 0 5px;
  cursor: pointer;
}

.navlink:hover {
  color: brown;
}

.posts--container {
  position: relative;
  display: grid;
  max-width: 800px;
  margin: auto;
  padding-top: 100px;
  gap: 4em;
}

.card {
  height: 100%;
  -webkit-box-shadow: 0px 1px 5px 0px rgba(183, 192, 206, 0.4);
  -moz-box-shadow: 0px 1px 5px 0px rgba(183, 192, 206, 0.4);
  box-shadow: 0px 1px 5px 0px rgba(183, 192, 206, 0.4);
  width: 100%;
  border-radius: 5px;
  padding: 20px;
}


Enter fullscreen mode Exit fullscreen mode

In the classname nav-intersect I added an extra rule for old browsers that have issues with the box-shadow rule, but I commented it out, because my browser was fine the css rule, you can uncomment it of you like.

what we are going to do in this example.

When a user enters the page, the navbar doesn't have a box-shadow, but when the user starts scrolling, the navbar is fixed and the box-shadows shows up and remains visible. We are going to implement this using the Intersection Observer API.
P.S the layout isn't mobile responsive.

The page is going to look like this:-
Image description

Now, moving on to the main part of this tutorial. For you to be able to observe an element properly, you'll need to simply wrap it with another element that is just slightly bigger than the child element, because the wrapper and the child can't be of the same height or width or even size. From the name wrapper means it has to be wrapped or contained. This is why in the classname nav-wrapper the element height is slightly bigger than the child's height navbar--container.

Let's go to the html file and scroll to main--container in the next div it's classname is empty, add this name nav--wrapper to it. Nothing changes, this is the wrapper for the element we are going to observe, which is navbar--container.

Let's go into the js file.
We are going to create variables for saving parent wrapper and the child.

const parent = document.querySelector(".nav--wrapper");
const navbar = document.querySelector(".navbar--container");

Enter fullscreen mode Exit fullscreen mode

You call the Intersection Observer by calling it's contructor, new IntersectionObserver() it takes in two arguments, a callback and options.

The callback

This is the function executed whenever the target element is in view or not, it is influenced by the options object.

options

This is an object with properties for configuring when/where you want to react to the changes in the target element. it has the following properties:-

  • root
    The element that is used as the view port for observing the visibility of the target. Defaults to the view port if null.

  • rootMargin
    This is the margin around the root, it's usually in px or percentages.

  • threshold
    Either a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed. If you only want to detect when visibility of the element is 50%, i.e you can pass a a value of 0.5. if you want the callback to run every time the visibility passes another 10%, you would specify the array to be [0, 0.10, 0.20, 0.30, ... 1]. A value of 1.0 means that threshold isn't considered passed until every pixel is visible, this is why the parent wrapper has to be slightly bigger to that it can show the element accurately.

Now, let's create an options object.

let options = {
  root: null,
  rootMargin: "0px",
  threshold: [0.0, 1.0],
};

Enter fullscreen mode Exit fullscreen mode

For the callback, the takes in an a list of entries as an argument, I'm just going to call an arrow function, add this to your code.

let navbarObserver = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (!entry.isIntersecting) {
      navbar.classList.add("nav-intersect");
      return;
    }
    navbar.classList.remove("nav-intersect");
  });
}, options);

Enter fullscreen mode Exit fullscreen mode

First, we created an instance of the IntersectionObserver then put the callback and options as arguments in the instance we just created. Then in the callback, we have access to entries (it describes the intersection between the target element and its root container at a specific moment of transition) using properties to check for those description, for example when the target element is intersecting, we use the isIntersecting property.

Next, we loop through those entries and we make an condition, since we are trying to show the navbar when it's no longer in view. we can negate the isIntersecting property. This will check, if the navbar element is going to be no longer in view, simply add it back.

Now we need to observe this element by calling the observe property on the Intersection Observer instance.

navbarObserver.observe(document.querySelector(".nav--wrapper"));

Enter fullscreen mode Exit fullscreen mode

This is all the code in js file.

const parent = document.querySelector(".nav--wrapper");
const navbar = document.querySelector(".navbar--container");

let options = {
  root: null,
  rootMargin: "0px",
  threshold: [0.0, 1.0],
};

let navbarObserver = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (!entry.isIntersecting) {
      navbar.classList.add("nav-intersect");
      return;
    }
    navbar.classList.remove("nav-intersect");
  });
}, options);

navbarObserver.observe(document.querySelector(".nav--wrapper"));

Enter fullscreen mode Exit fullscreen mode

You should see a box-shadow added to the navbar whenever you scroll through the page.

I couldn't have done this post without mdn's docs on the Intersection Observer API, you should check it out too!, click here, it's pretty long but with the basic example we did here, you should be able to catch up.

I hope you enjoyed this article!

Top comments (0)