JSFiddle - React, Tailwind, and code Playground
by mamounothman
HTML
<div class="container">
<p class="hi">There should always be four blue boxes in one row. Scroll down and back up</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>
</div>
CSS
body {
text-align: center;
}
.hi {
padding: 40vh 0;
background: lightblue;
width: 100%;
}
.container {
display:flex;
flex-wrap: wrap;
}
.box {
width: 23%; /* change this to 100% and it works fine */
height: 40vh;
margin-bottom: 10px;
background: blue;
}
.viewme {
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.15, 0.2, 0.25, 0.3]
};
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 viewbox = document.querySelectorAll('.viewme');
viewbox.forEach(image => {
observer.observe(image);
});