css based solution
css-scroll-snap
native, accessible, bolt on
cons: no custom animations.. is that true, can you tie into it maybe?
Scroll Hijacking Options for Slide Deck Experience
What is Scroll Hijacking?
Scroll hijacking (also called “scroll locking” or “scroll control”) is a technique where you intercept the browser’s default scroll behavior and replace it with custom animations or transitions. Instead of smooth scrolling, you get:
- Snap-to-slide behavior - Scroll “locks” onto each full-page slide
- Animation between slides - Transitions, fades, or other effects
- Partial scroll reveals - User scrolls partway, then animation completes the transition
- Programmatic control - JavaScript controls when slides change, not just scroll position
Example: User scrolls down 20%, JavaScript detects this, then animates a smooth transition to the next slide and “locks” there.
Option 1: CSS Scroll Snap (Native, No JavaScript)
What it is: Native CSS feature that snaps scrolling to specific points.
Implementation:
.slide-container {
scroll-snap-type: y mandatory;
overflow-y: scroll;
height: 100vh;
}
.slide {
scroll-snap-align: start;
height: 100vh;
}Pros:
- ✅ Native browser support - No JavaScript needed
- ✅ Performance - Hardware accelerated, smooth
- ✅ Accessible - Works with keyboard navigation, screen readers
- ✅ Simple - Just CSS, easy to implement
- ✅ Mobile-friendly - Works great on touch devices
Cons:
- ❌ Limited control - Can’t add custom animations between slides
- ❌ No partial scroll - Snaps immediately, no “scroll 20% then animate” behavior
- ❌ No scroll locking - User can still scroll past if they scroll fast
- ❌ Basic transitions - Only snap, no fade/slide animations
Best for: Simple slide decks where you just want snap-to-slide behavior.
Option 2: fullPage.js Library
What it is: Popular JavaScript library specifically for full-page scrolling websites.
Website: https://github.com/alvarotrigo/fullpage.js
Installation:
npm install fullpage.jsUsage:
new fullpage('#fullpage', {
sectionsColor: ['#f8f8f7', '#c6c6b9', '#272726'],
navigation: true,
scrollOverflow: true,
onLeave: (origin, destination) => {
// Custom animations here
}
});Pros:
- ✅ Feature-rich - Navigation dots, keyboard controls, hash URLs
- ✅ Well-documented - Extensive docs and examples
- ✅ Active maintenance - Regularly updated
- ✅ Responsive - Works on mobile/tablet/desktop
- ✅ Animations - Built-in transition effects
- ✅ Community - Large user base, lots of examples
Cons:
- ❌ Heavy dependency - Adds ~50KB+ to bundle
- ❌ Opinionated - May conflict with your design system
- ❌ jQuery dependency (older versions) - Newer versions are vanilla JS
- ❌ Less flexible - Harder to customize deeply
- ❌ Overkill - Might be more than you need
Best for: When you want a complete solution with minimal custom code.
Option 3: Locomotive Scroll
What it is: Modern, lightweight scroll library with smooth scrolling and scroll-triggered animations.
Website: https://github.com/locomotivemtl/locomotive-scroll
Installation:
npm install locomotive-scrollUsage:
import LocomotiveScroll from 'locomotive-scroll';
const scroll = new LocomotiveScroll({
el: document.querySelector('[data-scroll-container]'),
smooth: true,
scrollbarContainer: document.querySelector('[data-scroll-container]'),
});Pros:
- ✅ Smooth scrolling - Buttery smooth, hardware accelerated
- ✅ Lightweight - Smaller than fullPage.js
- ✅ Modern - Built for modern browsers
- ✅ Flexible - Easy to customize
- ✅ Scroll-triggered animations - Can trigger animations on scroll
- ✅ Good performance - Optimized for 60fps
Cons:
- ❌ Not slide-specific - More general-purpose, not built for slide decks
- ❌ Requires setup - Need to configure scroll containers
- ❌ Less slide features - No built-in navigation dots, hash URLs
- ❌ Custom work needed - You build the slide locking logic
Best for: When you want smooth scrolling with custom slide behavior.
Option 4: Custom JavaScript (Vanilla or Framework)
What it is: Build your own scroll hijacking system from scratch.
Implementation approach:
let currentSlide = 0;
const slides = document.querySelectorAll('.slide');
const isScrolling = false;
window.addEventListener('wheel', (e) => {
e.preventDefault();
if (isScrolling) return;
if (e.deltaY > 0 && currentSlide < slides.length - 1) {
// Scroll down - go to next slide
goToSlide(currentSlide + 1);
} else if (e.deltaY < 0 && currentSlide > 0) {
// Scroll up - go to previous slide
goToSlide(currentSlide - 1);
}
});
function goToSlide(index) {
isScrolling = true;
currentSlide = index;
// Animate to slide
slides[index].scrollIntoView({ behavior: 'smooth' });
// Lock scroll during animation
setTimeout(() => {
isScrolling = false;
}, 1000);
}Pros:
- ✅ Full control - Complete control over behavior
- ✅ No dependencies - Zero bundle size impact
- ✅ Custom animations - Any animation library (GSAP, Framer Motion, etc.)
- ✅ Lightweight - Only what you need
- ✅ Framework-agnostic - Works with any setup
Cons:
- ❌ Time-consuming - Significant development time
- ❌ Edge cases - Need to handle touch, keyboard, accessibility
- ❌ Maintenance - You own all the code
- ❌ Testing - Need to test across devices/browsers
- ❌ Complexity - Can get complicated quickly
Best for: When you need specific behavior that libraries don’t provide, or want zero dependencies.
Option 5: GSAP ScrollTrigger + ScrollSmoother
What it is: Professional animation library with powerful scroll control plugins.
Website: https://greensock.com/scrolltrigger/ | https://greensock.com/scrollsmoother/
Installation:
npm install gsapUsage:
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { ScrollSmoother } from 'gsap/ScrollSmoother';
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
ScrollSmoother.create({
wrapper: '#smooth-wrapper',
content: '#smooth-content',
smooth: 1.5,
effects: true,
});
// Custom slide locking with ScrollTrigger
slides.forEach((slide, index) => {
ScrollTrigger.create({
trigger: slide,
start: 'top top',
end: 'bottom top',
pin: true,
pinSpacing: false,
});
});Pros:
- ✅ Powerful animations - Industry-standard animation library
- ✅ Smooth scrolling - ScrollSmoother for buttery smoothness
- ✅ Scroll-triggered - Perfect for scroll-based animations
- ✅ Professional - Used by major brands
- ✅ Flexible - Can build any scroll behavior
- ✅ Performance - Highly optimized
Cons:
- ❌ Cost - ScrollSmoother requires paid license for commercial use
- ❌ Learning curve - GSAP has its own API to learn
- ❌ Bundle size - GSAP + plugins can be ~50KB+
- ❌ Overkill - Might be more than needed for simple slide decks
Best for: When you need professional-grade animations and have budget for licensing.
Recommendation for Your Project
Given your requirements:
- ✅ Slide deck presentation style
- ✅ Partial scroll then animation lock
- ✅ Designer-led project (needs to be maintainable)
- ✅ Astro (static site, minimal JS)
I’d recommend: Option 1 (CSS Scroll Snap) + Option 4 (Custom JS for locking)
Why:
- Start with CSS Scroll Snap - Get basic snap behavior working immediately
- Add minimal custom JS - Just add scroll locking logic (prevent scroll during transitions)
- Add animations - Use CSS transitions or a lightweight animation library
This gives you:
- ✅ Native performance (CSS scroll snap)
- ✅ Custom control (JS for locking)
- ✅ Minimal dependencies
- ✅ Easy to maintain
Alternative: If you want a complete solution quickly, Option 2 (fullPage.js) is the fastest path, but adds a dependency.
Next Steps
- Start simple: Implement CSS scroll snap first
- Test behavior: See if native snap is enough
- Add locking: If you need partial scroll + animation, add custom JS
- Consider library: If custom gets complex, evaluate fullPage.js