0

Basically, i have fixed button on bottom that scrolls over the page on mobile. The color of button is yellow and i want when the button scrolls over sections that are same color as button, to get additional class or change style directly inline and set BG color to white. Is it possible with Observer or something similar? Thanks!

  • you can use `mix-blend-mode: difference;` in the button CSS style or add a specific class name to elements that have the same background color as the button then check it by Javascript if the button crosses over those elements that have the specific class name add new style to the button. – Ramin eghbalian Apr 21 '22 at 14:39

1 Answers1

1

The trouble with trying to use the Intersection Observer API in this case is twofold:

  1. The yellow sections are not ancestors of the button, they're likely siblings.

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element...

  1. The button is position: fixed, which doesn't play nicely with the internals of the API: Intersection observer does not work with target with position: fixed.

The old-school way of doing this would be to check the bounding box of the button against the bounding boxes of the yellow sections each time the page is scrolled.

That means calling Element.getBoundingClientRect() once for the button (it's bounding box should never change because it's position: fixed relative to the viewport) and once for each yellow section each time the scroll event is raised.

Here's a sample showing this approach:

const button = document.getElementById('some-action');
const buttonRect = button.getBoundingClientRect();
  
const yellowDivs = document.querySelectorAll('div.yellow');

const areIntersecting = (bounds1, bounds2) => 
  bounds1.top < bounds2.bottom && bounds1.bottom > bounds2.top;

document.addEventListener('scroll', () => {

  /* Use for...of, not .forEach so we can
     return early. */
  for (let item of yellowDivs) {
    const itemRect = item.getBoundingClientRect();
        
    if (areIntersecting(itemRect, buttonRect)) {
      button.classList.add('white');
      button.classList.remove('yellow');
      
      /* We don't care how many yellow divs the button
         is intersecting. Once we've found one, we can
         return so we're not computing the rectangles
         of the rest. */
      return;    
    }
    
    /* If none of the yellow divs were interecting,
       reset the color of the button. */
    button.classList.add('yellow');
    button.classList.remove('white');
  }
});
div.blue, div.white, div.yellow { height: 250px; }
.blue { background-color: blue; }
.white { background-color: white; }
.yellow { background-color: yellow; }

#some-action {
  position: fixed;
  top: 20px;
  right: 20px;
  padding: 10px 20px;
}
<div class="blue"></div>
<div class="yellow"></div>
<div class="white"></div>
<div class="blue"></div>
<div class="yellow"></div>
<div class="white"></div>
<div class="blue"></div>
<div class="yellow"></div>
<div class="white"></div>
<div class="blue"></div>
<div class="yellow"></div>
<div class="white"></div>
<div class="blue"></div>
<div class="yellow"></div>
<div class="white"></div>
<button id="some-action" class="yellow">Some Action</button>
D M
  • 5,769
  • 4
  • 12
  • 27
  • This should work perfectly, I will let you know if i succeeded, thanks :) Just one question, will this work if sections have paddings top and bottom? – mArkoNNNi22 Apr 21 '22 at 16:55
  • Yes, it will work if the sections have padding. From the docs: "The returned value is a `DOMRect` object which is the smallest rectangle which contains the entire element, **including its padding** and border-width." – D M Apr 21 '22 at 18:44