Intersection API
This is a list
siamo quasi
eccolo
Intersection Observer API
The Intersection Observer is a web platform API, included in JS and without running in the main thread.
it asynchronously observe intersections between the target elements and the user viewpoint root:
//viewpoint set in options and target set in observe()
//IntersectionObs config can't be changed once set but can observe multiple
let base = useRef()
let target = useRef()
let interObs = useRef();
useEffect(()=>{
let options={
root: base.current, //Document/Element bounding-box used as viewpoint
rootmargin: "0px", //offset margins applied to viewpoint intersections
//interception area percentages that trigger the callback.
threshold: [...Array(100).keys()].map(x => x / 100)
}
//The argument being the observe() target elements
//of which only some are entries[0].isIntersecting
function entered(entries){
console.log( entries[0] )
}
interObs.current = new IntersectionObserver(entered, options)
interObs.current.observe(target.current)
}, [])
We need the IntersectionObserver() object and the target to unobserve() :
//remember to declare both outside useEffect()
//If used twice it returns an error, and won't work in <strictMode/>
//We use useRef() to keep the intersectionObserver() value after animations
function annulla(){
interObs.current.unobserve(target.current)
}
We observe() loop when there are multiple intersection targets.
let sections = document.querySelectorAll(".sticky-container")
sections.forEach((element)=> {
observer.observe(element)
})
We can use rootMargin to create a 0px top intersect for the root.
//used to intersect a sticky top element without scroll or height
let options={
root: contain.current,
rootMargin: '0px 0px -100% 0px'
}
The entries of the callback function will be the current inView from the root, with true/false isIntersect based on the (options).
The toggle() method force argument only adds/removes on true/false. We can add a scroll() event with the callback function, but it won't return any target data.
//We forEach() the entries to toggle() first
function passed(entries){
root.current.addEventListener('scroll', inside)
entries.forEach((element)=>{
element.target.classList.toggle('active', element.isIntersecting)
})
}
//To add a scroll-like intersection trigger we use an array of small thresholds
options:{
threshold: [...Array(100).keys()].map((x)=> x/100)
}
We can modify both the root and target without needing to change the intersectObserver().

This is how we animate intersectionObserver() nav-items.
Instead of the href/id scroll, we can manually scrollInView the section elements using offsetTop.
//This won't move the window page scroll in any way
//The offsetTop requires position-absolute on the scroll to be precise
function mosso(event){
event.preventDefault()
let container = event.target
let adesso = document.querySelector(`section#${container.classList[0]}`);
let moment = adesso.offsetTop + 10
adesso.parentNode.scrollTop = moment
}
The absolute scroll area won't return any height to its relative parent container, so we use document.offsetHeight for design's sake.
//Use margins on the relative to not modify the absolute offsetHeight
let sopra = useRef()
let sotto = useRef()
sopra.current.style.height = sotto.current.offsetHeight + "px"
<div ref={sopra} className="position-relative d-flex justify-content-center">
<div ref={sotto} className="position-absolute row mx-0 col-8">
</div>
</div>
We cache IntersectionObserver ID querySelect() outside the intersect function for easier manipulation and access.
//The forEach observer target
let finalmente = document.querySelectorAll(".stratos")
//The cache outside the intersectionObserver function
let navElems = {}
finalmente.forEach((navId) => {
navElems[navId.id] = document.querySelector(`.nav-item.${navId.id}`)
})
//So when it's time to edit the DOM element we
elements[entry.target.id].classList.add("active")
//document.querySelector(`.nav-item.${entry.target.id }`).classList.add("active")
Intersection CSS style animation
Check this webpage:
We animate the sections with toggle() css keyframes.
//Unlike useSpring() it won't animate on removal.
entry.target.classList.toggle("active", entry.isIntersecting)
.zone .row.active{
animation: example 0.5s;
}
@keyframes example{
0% {transform: scale(0);}
100% {transform: scale(1);}
}
We can access tag attributes or modify the entry.target.style directly.
<div class="imagi pure-g" data-color="#f1bace">
entry.target.style.backgroundColor = entry.target.getAttribute("data-color");;
//We check for a single className
if(entry.isIntersecting){
entry.target.classList.value.includes("panini") ?
entry.target.style.opacity = 1 : entry.target.style.opacity = 0
}
1
We apply the Intersection Observer API on the <Parallax> root, to limit the intersection to the scroll window of its layers, and not the entire page.
//We can getElementById() it from a <ParallaxLayer> component.
useEffect(()=>{
let window= document.getElementById("questo")
let options= {
root: window,
rootMargin: "0px 0px -100% 0px",
threshold: 0,
}
}
<Parallax pages={3.3} className="meno" ref={ultimo} id="questo">
<ParallaxLayer offset={0} style={{ backgroundColor: "lightskyblue" }}>
<Secondo/>
</ParallaxLayer>
...
</Parallax>
Last updated
Was this helpful?