JSFiddle - React, Tailwind, and code Playground
by Sub Lines
HTML
<p class="hi">Scroll down</p>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
CSS
.hi {
padding: 40vh 0;
}
.box {
width: 100%;
height: 40vh;
margin-bottom: 10px;
background: blue;
transition: opacity .2s ease;
display: flex;
justify-content: center;
align-items: center;
font-size: 3em;
opacity: 0;
transform: translateY(20px);
transition: all .3s ease;
}
.inview-top, .inview-bottom {
opacity: 1;
transform: translateY(0);
}
.outview-top {
opacity: 0;
transform: translateY(-20px);
}
.outview-bottom {
opacity: 0;
transform: translateY(20px);
}
JavaScript
const config = {
root: null,
rootMargin: '0px',
threshold: [0.1]
};
let previousY = 0;
let previousRatio = 0;
let observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
const currentY = entry.boundingClientRect.y
const currentRatio = entry.intersectionRatio
const isIntersecting = entry.isIntersecting
const element = entry.target;
element.classList.remove("outview-top", "inview-top", "inview-bottom", "outview-bottom");
// Scrolling up
if (currentY < previousY) {
const className = (currentRatio >= previousRatio) ? "inview-top" : "outview-top";
element.classList.add(className);
// Scrolling down
} else if (currentY > previousY) {
const className = (currentRatio <= previousRatio) ? "outview-bottom" : "inview-bottom";
element.classList.add(className);
}
previousY = currentY
previousRatio = currentRatio
})
}, config);
const images = document.querySelectorAll('.viewme');
images.forEach(image => {
observer.observe(image);
});