Home > Enterprise >  Add/remove class to div if section is in viewport (vanilla JS)
Add/remove class to div if section is in viewport (vanilla JS)

Time:10-15

I have a onepager with 5 sections, each with a min-height of 100vh and an id. Then there is a fixed background div that changes its state when a new section comes into the viewport.

<div class="background"></div>

<section id="s1">...</section>
<section id="s2">...</section>
<section id="s3">...</section>
<section id="s4">...</section>
<section id="s5">...</section>

I wanted to update the background div with a class with the name of the current section id when the section enters the viewport and remove it when the section leaves the viewport.

This is what I made:

const sections = document.querySelectorAll('section')
const bg = document.querySelector('div.background')

document.addEventListener('scroll', updateBg)

function updateBg() {
  sections.forEach((section) => {
    const pixels = window.pageYOffset
    const sectionId = section.getAttribute('id')
    const offsetBottom = section.offsetTop   section.offsetHeight

    if (section.offsetTop <= pixels) {
      bg.classList.add(sectionId)
    }

    else if (offsetBottom >= pixels) {
        bg.classList.remove(sectionId)
      }

    else {
      bg.classList.remove(sectionId)
    }
  })
}

Adding the current class when the section enters the viewport works fine. But it's not removing the classes when the sections have left the viewport like I declared in my else if (offsetBottom >= pixels) statement. When I fully scrolled down the page I have something like this:

<div ></div>

but what I want at the end is this: <div ></div>

any help?

CodePudding user response:

Your conditions seem to be out of order. You are setting the class for all sections that are below the scroll threshold. Instead, you should add the class if part of the section is visible and remove it otherwise, like this:

if (section.offsetTop <= pixels && offsetBottom > pixels) {
  bg.classList.add(sectionId);
} else {
  bg.classList.remove(sectionId)
}

Also, please read the answer to this question: How can I tell if a DOM element is visible in the current viewport? It is recommended to use getBoundingClientRect API instead.

  • Related