JSFiddle - React, Tailwind, and code Playground
by HDL52
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.3/ScrollTrigger.min.js"></script>
<div class='container'>
<div class='reveal'>
<img src='https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/imgied0v0dgsgyqeoh7804b0ca54buj0qd.jpg'>
</div>
</div>
<div class='container'>
<div class='reveal'>
<img src='https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/imge39twvhffwemdsipqncbwko5vayrxgd.jpg'>
</div>
</div>
<div class='container'>
<div class='reveal'>
<img src='https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/img1u6qw3ad64bz8nsedrd2wddgrax5wew.jpg'>
</div>
</div>
<div class='container'>
<div class='reveal'>
<img src='https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/img克鲁赛德战记-A.jpg'>
</div>
</div>
SCSS
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
position: relative;
}
.container:nth-child(1) {
background: #b6916d;
}
.container:nth-child(2) {
background: #bcb8ad;
}
.container:nth-child(3) {
background: #b69187;
}
.container:nth-child(4) {
background: #3c564f;
}
img {
height: 100%;
width: 100%;
object-fit: cover;
transform-origin: left;
}
.reveal {
visibility: hidden;
position: relative;
width: 80%;
height: 80%;
max-width: 800px;
overflow: hidden;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
JavaScript
// https://codepen.io/cameronknight/pen/pogQKwR
gsap.registerPlugin(ScrollTrigger);
let revealContainers = document.querySelectorAll(".reveal");
revealContainers.forEach((container) => {
let image = container.querySelector("img");
let tl = gsap.timeline({
scrollTrigger: {
trigger: container,
toggleActions: "restart none none reset"
}
});
tl.set(container, { autoAlpha: 1 });
tl.from(container, 1.5, {
xPercent: -100,
ease: Power2.out
});
tl.from(image, 1.5, {
xPercent: 100,
scale: 1.3,
delay: -1.5,
ease: Power2.out
});
});
// OLD WAY USING INTERSECTION OBSERVER API AND CLIP-PATH
/*const options = {
root: null,
rootMargin: "0px",
threshold: 0.9
};
let revealCallback = (entries, self) => {
entries.forEach(entry => {
let container = entry.target;
let img = entry.target.querySelector("img");
const easeInOut = "power3.out";
const revealAnim = gsap.timeline({ ease: easeInOut });
if (entry.isIntersecting) {
revealAnim.set(container, {
visibility: "visible"
});
revealAnim.fromTo(
container,
{
clipPath: "polygon(0 0, 0 0, 0 100%, 0% 100%)",
webkitClipPath: "polygon(0 0, 0 0, 0 100%, 0% 100%)"
},
{
clipPath: "polygon(0 0, 100% 0, 100% 100%, 0 100%)",
webkitClipPath: "polygon(0 0, 100% 0, 100% 100%, 0 100%)",
duration: 1,
ease: easeInOut
}
);
revealAnim.from(img, 4, {
scale: 1.4,
ease: easeInOut,
delay: -1
});
self.unobserve(entry.target);
}
});
};
let revealObserver = new IntersectionObserver(revealCallback, options);
document.querySelectorAll(".reveal").forEach(reveal => {
revealObserver.observe(reveal);
});
*/