Considering my perspective, one approach is to include overflow-y: auto
in the parent element's styling. Additionally, modifying the line
const html = document.documentElement;
to target the specific parent element (e.g.,
const html = document.getElementById("wrap1");
) as suggested. Subsequently, attaching a scroll listener to the parent by changing
window.addEventListener('scroll', () => {
to
html.addEventListener('scroll', () => {
. Following these adjustments, the image animation should respond to the parent's scrolling behavior, exemplified below:
const html = document.getElementById("wrap1");
const canvas = document.getElementById("hero-lightpass");
const context = canvas.getContext("2d");
const frameCount = 148;
const currentFrame = index =>
(`https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`);
const preloadImages = () => {
for (let i = 1; i < frameCount; i++) {
const img = new Image();
img.src = currentFrame(i);
}
};
const img = new Image();
img.src = currentFrame(1);
canvas.width = 1158;
canvas.height = 770;
img.onload = function() {
context.drawImage(img, 0, 0);
};
const updateImage = index => {
img.src = currentFrame(index);
context.drawImage(img, 0, 0);
}
html.addEventListener('scroll', () => {
const scrollTop = html.scrollTop;
const maxScrollTop = html.scrollHeight - window.innerHeight;
const scrollFraction = scrollTop / maxScrollTop;
const frameIndex = Math.min(frameCount - 1, Math.ceil(scrollFraction * frameCount));
requestAnimationFrame(() => updateImage(frameIndex + 1));
});
preloadImages();
#wrap1 {
z-index: 1;
margin: 0;
padding: 0;
background: #000;
overflow-y: auto;
max-height: 100vh;
}
#wrap {
height: 500vh;
}
#wrap2 {
position: relative;
}
canvas {
position: absolute;
max-width: 100%;
max-height: 100vh;
top: 50%;
pointer-events: none;
transform: translate(calc(-50% - 20px), -50%); /* add scrollbar width 20px so that it's visible */
left: 50%;
}
body {
margin: 0;
}
<div id="wrap2">
<div class="wrap1" id="wrap1">
<div class="wrap" id="wrap">
<canvas id="hero-lightpass"></canvas>
</div>
</div>
</div>
Note: I made some alterations in the CSS code structure to resemble that of the provided snippet.