<div class="spacer">
<h2>Scroll Down</h2>
<p>The gallery section will pin to the top and scroll sideways.</p>
</div>
<div class="scroll-container" id="scroll-container">
<div class="sticky-view">
<div class="horizontal-track" id="scroll-track">
<div class="gallery-card">
<img src="https://placehold.co/400x500/3b82f6/ffffff?text=One" alt="Image">
</div>
<div class="gallery-card">
<img src="https://placehold.co/400x500/10b981/ffffff?text=Two" alt="Image">
</div>
<div class="gallery-card">
<img src="https://placehold.co/400x500/f59e0b/ffffff?text=Three" alt="Image">
</div>
<div class="gallery-card">
<img src="https://placehold.co/400x500/ef4444/ffffff?text=Four" alt="Image">
</div>
<div class="gallery-card">
<img src="https://placehold.co/400x500/8b5cf6/ffffff?text=Five" alt="Image">
</div>
</div>
</div>
</div>
<div class="spacer">
<h2>Keep Scrolling</h2>
<p>You have passed the horizontal section.</p>
</div>
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
margin: 0;
background: #111827;
color: #ffffff;
}
.spacer {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
.scroll-container {
height: 400vh;
position: relative;
}
.sticky-view {
position: sticky;
top: 0;
height: 100vh;
width: 100%;
overflow: hidden;
display: flex;
align-items: center;
}
.horizontal-track {
display: flex;
gap: 40px;
padding: 0 40px;
will-change: transform;
}
.gallery-card {
width: 350px;
height: 500px;
flex-shrink: 0;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}
.gallery-card img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
const container = document.getElementById("scroll-container");
const track = document.getElementById("scroll-track");
window.addEventListener("scroll", function() {
const rect = container.getBoundingClientRect();
const top = rect.top;
// Calculate total scrollable distance inside the container
const maxScroll = rect.height - window.innerHeight;
// Check if we are currently scrolling past the container
if (top <= 0 && top >= -maxScroll) {
const progress = -top / maxScroll;
// Calculate how far the track needs to move horizontally
const trackWidth = track.scrollWidth - window.innerWidth;
const moveX = progress * trackWidth;
track.style.transform = "translateX(-" + moveX + "px)";
}
});