Ray  Paras
Ray Paras

Reputation: 157

IntersectionObserver, how to Intersect full height of elements observing using Javascript

hello there i have a problem. i want to full intersect of selected observing element height. not half or double intersect like below in the picture two elements has been intersected when im scrolling i want only who is full height when i scroll

enter image description here

here is my HTML code

<ul>
  <li><a href="#one" class="active">P1</a></li>
  <li><a href="#two">P2</a></li>
  <li><a href="#three">P3</a></li>
  <li><a href="#four">P4</a></li>
</ul>
<div id="one">
  <p>P1 </p>
  <section>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</section>
</div>

<div id="two">
  <p>P2 </p>
  <section>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</section>
</div>

<div id="three">
  <p>P3 </p>
  <section>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</section>
</div>

<div id="four">
  <p>P4 </p>
  <section>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</section>
</div>

here is my Javascript code

  let observer = new IntersectionObserver(beTouching)

  document.querySelectorAll('div').forEach(div=>{
    observer.observe(div)
  })

  function beTouching(elements){
    elements.forEach(element=>{
      if(element.isIntersecting&&element.boundingClientRect.height){
        console.log(element.target)
         let id  = element.target.getAttribute('id')
         document.querySelector('ul li a[href*='+id+']').classList.add('active');
      }else{
        let id  = element.target.getAttribute('id')
         document.querySelector('ul li a[href*='+id+']').classList.remove('active');
      }
    })
  }

here is my Css code

*{
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  text-decoration: none;
  scroll-behavior: smooth;

}
body{

}
div#one{
  background: cornflowerblue;
  height: 100vh;
}
div#two{
  background: coral;
  height: 100vh;
}
div#three{
  background: pink;
  height: 100vh;
}
div#four{
  background: skyblue;
  height: 100vh;
}
.active{
  background: red !important;
  color: white !important;
  padding: 20px;
}
ul{
  height: 50px;
  width: 100%;
  background: green;
  display: flex;
  list-style-type: none;
  justify-content: space-around;
  align-items: center;
  position: sticky;
  top: 0px;
}

Upvotes: 0

Views: 664

Answers (1)

ivanatias
ivanatias

Reputation: 4033

From what I understand, you want your Nav links to be highlighted whenever the section they are linked to is visible in the viewport and also, avoiding two Nav links being highlighted at the same time.

You can achieve this with some slight modifications and using the rootMargin of the intersection observer.

Intersection observer callback:

function beTouching (elements) {
  elements.forEach(element=> {
    const id = element.target.getAttribute('id')
    const menuLink = document.querySelector(`ul li a[href='#${id}']`)

    if(element.isIntersecting) {
      document.querySelector('ul li a.active').classList.remove('active')
      menuLink.classList.add('active')
    }
  })
}

In your intersection observer definition:

const observer = new IntersectionObserver(beTouching, {
  rootMargin: '-50% 0px'
})

Explanation:

Using a negative rootMargin for top and bottom margins, you're basically "reducing" the intersection section vertically, therefore, avoiding two sections that are both partially visible in the viewport to be intersected at the same time. Now, by doing this without this lines of code:

 if(element.isIntersecting) {
      document.querySelector('ul li a.active').classList.remove('active')
      menuLink.classList.add('active')
    }

What would happen is that at some point in the middle when you are scrolling, none of the sections will be intersecting, so no Nav links will be highlighted and this is an undesirable behaviour. So, you put as a condition that only if the element is intersecting, then proceed to remove the active class from the a tag corresponding to the section that was previously intersecting and add that active to the section that is currently intersecting.

Note: You can play around with the negative top and bottom margins to find a combination that works the best for you. If you try different values, make sure the sum of them is always equal to 100% (for example, -30% top, -70% bottom).

Upvotes: 1

Related Questions