slow-scroll
v0.0.7
Published
Super Slow Smooth Scroll
Maintainers
Readme
Super Slow Smooth Scroll
Enables smooth and slow scrolling across all browsers.
How It Works
Time: 0ms 16ms 33ms 50ms 66ms (next scroll)
│ │ │ │ │
Scroll: scrollBy(1px) scrollBy(1px)
│ │ │ │ │
Visual: translate(0) (-0.25px) (-0.5px) (-0.75px) translate(0)
│ │ │ │ │
Result: [------------- Appears smooth at 60fps -------------]The target element uses translateY to visually interpolate between actual scroll updates, appearing smooth at the device's native refresh rate.
Installation
npm
npm install slow-scrollimport createSlowScroll from "slow-scroll";
const scroller = SlowScroll.createSlowScroll({
target: "#container",
speed: 30,
bounce: true,
});CDN
<!-- Load from CDN -->
<script src="https://unpkg.com/slow-scroll@latest/dist/slow-scroll.umd.js"></script>
<script>
const scroller = SlowScroll.createSlowScroll({
target: "#container",
speed: 30,
bounce: true,
});
</script>Note: When using the CDN version, the library is available as SlowScroll global variable.
Usage
Basic Example
// Simplest usage - scrolls body automatically
const scroller = createSlowScroll();
// With custom options
const scroller = createSlowScroll({
target: ".content", // Scrollable container (defaults to 'body')
interpolationTarget: ".inner", // Element to apply interpolation (optional, defaults to target)
speed: 30, // Pixels per second - positive = down/right, negative = up/left (default: 30)
interpolation: true, // Enable interpolation (default: true)
bounce: false, // Reverse at boundaries (default: false)
isHorizontal: false, // Scroll horizontally instead of vertically (default: false)
autoplay: true, // Start automatically (default: true)
});
// Stop scrolling when needed
scroller.stop();
// Restart if stopped
scroller.start();Recommended speed: 15-30 px/s for best balance between smoothness and performance.
Separate Interpolation Target
By default, interpolation transforms are applied to the scrollable element itself. However, in complex layouts with fixed headers, sidebars, or other non-scrolling elements, you may notice unwanted visual jitter or stutter on those elements.
Use interpolationTarget to apply the smooth interpolation only to the content area, preventing unwanted transform effects on other parts of your layout:
const scroller = createSlowScroll({
target: ".scrollable-container", // Element with overflow: auto
interpolationTarget: ".inner-content", // Only this element gets the smooth interpolation
speed: 20,
interpolation: true,
});Use this when:
- You have fixed headers, footers, or sidebars that shouldn't be affected by the transform
- You notice visual jitter or stuttering on elements that shouldn't move
- You have a complex layout where only specific content should receive the smooth effect
Manual Control (Without Autoplay)
const scroller = createSlowScroll({
target: ".content",
speed: 30,
autoplay: false, // Disable autoplay
});
// Start manually when needed
document.getElementById("startBtn").addEventListener("click", () => {
scroller.start();
});
document.getElementById("stopBtn").addEventListener("click", () => {
scroller.stop();
});With Bounce Effect ↕︎
const scroller = createSlowScroll({
target: ".content",
speed: 24, // 24 pixels per second
bounce: true, // Enable bounce at boundaries
onDirectionChange: (direction) => {
console.log(`Now scrolling: ${direction}`); // 'up', 'down', 'left', or 'right'
},
});
// Starts automaticallyNotes:
- When
bounceisfalse, scrolling stops when reaching page boundaries - When
bounceistrue, scroll direction automatically reverses at boundaries
Horizontal Scrolling →
const scroller = createSlowScroll({
target: ".horizontal-content",
isHorizontal: true, // Enable horizontal scrolling
speed: 30, // Scroll right at 30px/s
});
// Starts automaticallyReverse Direction Scrolling ↑←
Use negative speed values to scroll in the opposite direction:
// Scroll up instead of down
const upScroller = createSlowScroll({
target: ".content",
speed: -30, // Negative speed = scroll up
});
// Scroll left instead of right
const leftScroller = createSlowScroll({
target: ".horizontal-content",
isHorizontal: true,
speed: -30, // Negative speed = scroll left
});Pause on User Interaction
Pause scrolling when user touches or moves mouse over the scroll area:
const scroller = createSlowScroll({
target: ".content",
speed: 30,
pauseOnTouch: true, // Pause when user touches (useful for mobile/tablet)
pauseOnMouseMove: true, // Pause when mouse is moving (useful for desktop)
});
// Scrolling automatically resumes when user stops interactingUse cases:
pauseOnTouch: Prevents auto-scroll from interfering with user's touch scrolling on mobile devicespauseOnMouseMove: Pauses when user moves mouse, allowing them to interact with content- Both options work together - enable one or both based on your needs
Dynamic Speed Control
const scroller = createSlowScroll({
target: ".content",
speed: 30,
});
// Change speed dynamically (automatically restarts if running)
scroller.setSpeed(50); // Speed up to 50px/s
scroller.setSpeed(15); // Slow down to 15px/s
// Example: Speed control with buttons
document.getElementById("speedUpBtn").addEventListener("click", () => {
const config = scroller.getConfig();
scroller.setSpeed(config.speed + 10);
});
document.getElementById("slowDownBtn").addEventListener("click", () => {
const config = scroller.getConfig();
scroller.setSpeed(Math.max(5, config.speed - 10)); // Minimum 5px/s
});Without Interpolation (Compare Performance)
const scroller = createSlowScroll({
target: ".content",
speed: 15, // 15 pixels per second
interpolation: false, // Disable for comparison
onBoundaryReached: (boundary) => {
console.log(`Reached ${boundary}, stopping`); // 'top', 'bottom', 'left', or 'right'
},
});
// Starts automaticallyCheck Status
// Check if currently running
if (scroller.isRunning()) {
console.log("Scrolling is active");
}
// Get current configuration
const config = scroller.getConfig();
console.log(`Speed: ${config.speed}px/s, Horizontal: ${config.isHorizontal}`);API Reference
Methods
| Method | Parameters | Returns | Description |
| -------------------- | ------------------ | --------- | ----------------------------------------------------------------------------- |
| start() | None | void | Starts the auto-scrolling. Does nothing if already running. |
| stop() | None | void | Stops the auto-scrolling and resets transform states. |
| setSpeed(newSpeed) | newSpeed: number | void | Updates scroll speed in pixels per second. Automatically restarts if running. |
| isRunning() | None | boolean | Returns true if currently scrolling, false otherwise. |
| getConfig() | None | object | Returns a copy of the current configuration object. |
Configuration Options
| Option | Type | Default | Description |
| ----------------------- | ----------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| target | string \| HTMLElement | 'body' | CSS selector or DOM element of the scrollable container. |
| interpolationTarget | string \| HTMLElement | null | CSS selector or DOM element to apply interpolation transform. If not specified, uses target for window scrolling, or the scrollable container itself for element scrolling. |
| speed | number | 30 | Scroll speed in pixels per second (e.g., 24 = 24px/second). Positive values scroll down/right, negative values scroll up/left. Use 0 to pause. |
| interpolation | boolean | true | Enable transform interpolation for smooth visual experience. |
| bounce | boolean | false | Reverse scroll direction when reaching boundaries. |
| isHorizontal | boolean | false | Scroll horizontally instead of vertically. |
| autoplay | boolean | true | Start scrolling automatically when instance is created. |
| pauseOnTouch | boolean | false | Pause scrolling when user touches the scroll area (useful for mobile). |
| pauseOnMouseMove | boolean | false | Pause scrolling when mouse is moving over the scroll area. |
| userScrollResumeDelay | number | 100 | Time in milliseconds to wait before resuming auto-scroll after user scrolling stops (iOS/iPadOS only). Increase if momentum scrolling feels interrupted. |
| onDirectionChange | function | null | Callback function called when scroll direction changes (with bounce enabled). Receives new direction as parameter. |
| onBoundaryReached | function | null | Callback function called when boundary is reached (with bounce disabled). Receives boundary type as parameter. |
Development
Run Demo Locally
cd demo
npm install
npm run devOpens the demo at http://localhost:3000
License
MIT
Author
Yamato Iizuka
