javascriptintersection-observerweak-set

Create a WeakSet of all elements whose layout overflows documentElement


I want to create a WeakSet of all elements that are not 100% contained within the css layout bounds of the document root (<html> tag). I need it to update in real time and not have a huge hit on browser performance.

To achieve this I used the intersectionObserver API as follows below and this creates my WeakSet with all the elements I expect when I pass it document.querySelectorAll('body *')

My problem is that when I want to test if an element is in my WeakSet, I get the correct answer in Safari. However, both Chrome and FireFox always return false when I check a matching element using overflowedElements.has(el)

This appears to be due to Chrome/FireFox incorrectly creating a separate reference to the element via the IntersectionObserverEntry: target property, which then leads to there being two non-matching references to the same element.

Therefore I guess my question is how can I cheaply get the correct element references into my WeakSet, so I can match them in all browsers?

const options = {
  root: document.documentElement,
  rootMargin: '0px',
  threshold: 1,
}

const overflowedElements = new WeakSet()

const callback = (entries) => {
  entries.forEach((entry) => {
    if (entry.intersectionRatio !== 1) {
      overflowedElements.add(entry.target)
    } else {
      overflowedElements.delete(entry.target)
    }
  })
  console.log('overflowedElements', overflowedElements)
}

const observer = new IntersectionObserver(callback, options)

export const observeOverflow = (nodeList) => {
  nodeList.forEach((el) => {
    observer.observe(el)
  })
}

export const isOverflowed = (el) => overflowedElements.has(el)

Solution

  • In case anyone else ever needs to do this, the workaround was to use entry.target.toggleAttribute and then document.querySelectorAll to create a nodeList rather than a weakSet. Which in my case turned out to be more useful and better performing.