Modern and the sweet smooth scroll library.
npm install sweet-scroll



> ECMAScript2015+ & TypeScript Friendly, dependency-free smooth scroll library.
:lollipop: See Demo
- Dependecy-free!!
- ECMAScript2015+ & TypeScript friendly
- Use requestAnimationFrame API
- Supports vertical and horizontal scroll
- Supports dynamic trigger (event delegation)
- Supports container for the scroll
- Supports many easing types
- Supports server-side rendering (Can load without putting out errors.)
See the Migration Guide
- Usage
- 1. Install
- 2. Setup of HTML
- 3. Initialize SweetScroll
- Options
- Easings
- Built-in (22)
- Advanced (9)
- Customizing Tips
- Specifying container elements
- Specify fixed header
- Override of options for each element
- If you want to use in non anchor element
- Do you feel scrolling is slow?
- Scrolling animation in another page
- API
- new SweetScroll(options?: PartialOptions, container?: string | Element)
- SweetScroll.create(options?: PartialOptions, container?: string | Element)
- to(distance: any, options?: PartialOptions)
- toTop(distance: any, options?: PartialOptions)
- toLeft(distance: any, options?: PartialOptions)
- toElement(\$el: Element, options?: PartialOptions)
- update(options: PartialOptions)
- stop(gotoEnd: boolean = true)
- destroy()
- Callbacks
- Browser Support
- Scrolling with IE9
- CHANGELOG
- Contibute
- Development
- License
#### via NPM
``bash`
$ npm install sweet-scroll
##### use
`typescript`
import SweetScroll from 'sweet-scroll';
#### via MANUAL
1. Download the sweet-scroll.min.js
1. Load it in the script tag.
`html`
#### via CDN (UNPKG)
`html`
`html`
Go to Introduction
...Introduction
You need to initialize an instance after DOMContentLoaded.
`typescript`
document.addEventListener(
'DOMContentLoaded',
() => {
const scroller = new SweetScroll({
/ some options /
});
},
false,
);
The following options are applied by default. It can be customized as needed.
`typescript
{
trigger: '[data-scroll]', // Selector for trigger (must be a valid css selector)
header: '[data-scroll-header]', // Selector or Element for fixed header (Selector of must be a valid css selector)
duration: 1000, // Specifies animation duration in integer
easing: 'easeOutQuint', // Specifies the pattern of easing
offset: 0, // Specifies the value to offset the scroll position in pixels
vertical: true, // Enable the vertical scroll
horizontal: false, // Enable the horizontal scroll
cancellable: true, // When fired wheel or touchstart events to stop scrolling
updateURL: false, // Update the URL hash on after scroll (true | false | 'push' | 'replace')
preventDefault: true, // Cancels the container element click event
stopPropagation: true, // Prevents further propagation of the container element click event in the bubbling phase
// Callbacks
before: null,
after: null,
cancel: null,
complete: null,
step: null,
}
`
Supports the following easing.
- Normal
- lineareaseInQuad
- Quad
- easeOutQuad
- easeInOutQuad
- easeInCubic
- Cubic
- easeOutCubic
- easeInOutCubic
- easeInQuart
- Quart
- easeOutQuart
- easeInOutQuart
- easeInQuint
- Quint
- easeOutQuint
- (default)easeInOutQuint
- easeInSine
- Sine
- easeOutSine
- easeInOutSine
- easeInExpo
- Expo
- easeOutExpo
- easeInOutExpo
- easeInCirc
- Circ
- easeOutCirc
- easeInOutCirc
-
Easing functions that are not built in can pass functions directly.
`typescript`
const scroller = new SweetScroll({
easing: advancedEasingFunction,
});
#### Elastic
easeInElastic
`typescript`
const easeInElastic = (_, t, b, c, d) => {
let s = 1.70158;
let p = 0;
let a = c;
if (t === 0) return b;
if ((t /= d) === 1) return b + c;
if (!p) p = d * 0.3;
if (a < Math.abs(c)) {
a = c;
s = p / 4;
} else {
s = (p / (2 Math.PI)) asin(c / a);
}
return -(a Math.pow(2, 10 (t -= 1)) Math.sin(((t d - s) (2 Math.PI)) / p)) + b;
};
easeOutElastic
`typescript`
const easeOutElastic = (_, t, b, c, d) => {
let s = 1.70158;
let p = 0;
let a = c;
if (t === 0) return b;
if ((t /= d) === 1) return b + c;
if (!p) p = d * 0.3;
if (a < Math.abs(c)) {
a = c;
s = p / 4;
} else {
s = (p / (2 Math.PI)) asin(c / a);
}
return a Math.pow(2, -10 t) Math.sin(((t d - s) (2 Math.PI)) / p) + c + b;
};
easeInOutElastic
`typescript`
const easeInOutElastic = (_, t, b, c, d) => {
let s = 1.70158;
let p = 0;
let a = c;
if (t === 0) return b;
if ((t /= d / 2) === 2) return b + c;
if (!p) p = d (0.3 1.5);
if (a < Math.abs(c)) {
a = c;
s = p / 4;
} else {
s = (p / (2 Math.PI)) Math.asin(c / a);
}
if (t < 1) {
return (
-0.5 (a Math.pow(2, 10 (t -= 1)) Math.sin(((t d - s) (2 * Math.PI)) / p)) + b
);
}
return (
a Math.pow(2, -10 (t -= 1)) Math.sin(((t d - s) (2 Math.PI)) / p) * 0.5 + c + b
);
};
#### Back
easeInBack
`typescript`
const easeInBack = (_, t, b, c, d, s = 1.70158) => c (t /= d) t ((s + 1) t - s) + b;
easeOutBack
`typescript`
const easeOutBack = (_, t, b, c, d, s = 1.70158) =>
c ((t = t / d - 1) t ((s + 1) t + s) + 1) + b;
easeInOutBack
`typescript`
const easeInOutBack = (_, t, b, c, d, s = 1.70158) =>
(t /= d / 2) < 1
? (c / 2) (t t (((s = 1.525) + 1) * t - s)) + b
: (c / 2) ((t -= 2) t (((s = 1.525) + 1) * t + s) + 2) + b;
#### Bounce
easeOutBounce
`typescript`
const easeOutBounce = (_, t, b, c, d) => {
if ((t /= d) < 1 / 2.75) {
return c (7.5625 t * t) + b;
} else if (t < 2 / 2.75) {
return c (7.5625 (t -= 1.5 / 2.75) * t + 0.75) + b;
} else if (t < 2.5 / 2.75) {
return c (7.5625 (t -= 2.25 / 2.75) * t + 0.9375) + b;
}
return c (7.5625 (t -= 2.625 / 2.75) * t + 0.984375) + b;
};
easeInBounce
`typescript
const easeOutBounce = (_, t, b, c, d) => {
if ((t /= d) < 1 / 2.75) {
return c (7.5625 t * t) + b;
} else if (t < 2 / 2.75) {
return c (7.5625 (t -= 1.5 / 2.75) * t + 0.75) + b;
} else if (t < 2.5 / 2.75) {
return c (7.5625 (t -= 2.25 / 2.75) * t + 0.9375) + b;
}
return c (7.5625 (t -= 2.625 / 2.75) * t + 0.984375) + b;
};
const easeInBounce = (x, t, b, c, d) => c - easeOutBounce(x, d - t, 0, c, d) + b;
`
easeInOutBounce
`typescript
const easeOutBounce = (_, t, b, c, d) => {
if ((t /= d) < 1 / 2.75) {
return c (7.5625 t * t) + b;
} else if (t < 2 / 2.75) {
return c (7.5625 (t -= 1.5 / 2.75) * t + 0.75) + b;
} else if (t < 2.5 / 2.75) {
return c (7.5625 (t -= 2.25 / 2.75) * t + 0.9375) + b;
}
return c (7.5625 (t -= 2.625 / 2.75) * t + 0.984375) + b;
};
const easeInBounce = (x, t, b, c, d) => c - easeOutBounce(x, d - t, 0, c, d) + b;
const easeInOutBounce = (x, t, b, c, d) =>
t < d / 2
? easeInBounce(x, t 2, 0, c, d) 0.5 + b
: easeOutBounce(x, t 2 - d, 0, c, d) 0.5 + c * 0.5 + b;
`
---
In the following example we have specified in the container for scrolling the #container.
`html`
`typescript
// Specified in the CSS Selector
const scroller = new SweetScroll(
{
/ some options /
},
'#container',
);
// Specified in the Element
const scroller = new SweetScroll(
{
/ some options /
},
document.getElementById('container'),
);
`
Add the data-scroll-header attribute in order to offset the height of the fixed header.
`html`
Specify the CSS Selector in header option instead of the data-scroll-header attribute.
`typescript`
const scroller = new SweetScroll({
header: '#header',
});
You can override the default options by passing the option in JSON format to the data-scroll-options.
`html`
Go to Target
Will use the data-scroll attribute instead of href.
`html`
The following, Introduce one of the mounting method.
`typescript
document.addEventListener(
'DOMContentLoaded',
() => {
const scroller = new SweetScroll();
const hash = window.location.hash;
const needsInitialScroll = document.getElementById(hash.substr(1)) != null;
if (needsInitialScroll) {
window.location.hash = '';
}
window.addEventListener(
'load',
() => {
if (needsInitialScroll) {
scroller.to(hash, { updateURL: 'replace' });
}
},
false,
);
},
false,
);
`
You can also achieve the same thing in other ways by using the provided API.
Will generate a SweetScroll instance.
Example:
`typescript`
const scroller = new SweetScroll(
{
duration: 1200,
easing: 'easeOutExpo',
},
'#container',
);
Will generate a SweetScroll instance. (factory method)
Example:
`typescript`
const scroller = SweetScroll.create(
{
duration: 1200,
easing: 'easeOutExpo',
},
'#container',
);
Scroll animation to the specified distance.distance to can specify the CSS Selector or scroll position.
Example:
`typescript
const scroller = new SweetScroll();
// CSS Selector of target element
scroller.to('#footer');
// Object
scroller.to({ top: 1000, left: 20 });
// Array (top:0, left:1000)
scroller.to([0, 1000]);
// Number (Priority to vertical scroll position. by default.)
scroller.to(500);
// String (Relative position)
scroller.to('+=500');
scroller.to('-=200');
`
Vertical scroll animation to the specified distance.
Example:
`typescript`
scroller.toTop(0);
Horizontal scroll animation to the specified distance.
Example:
`typescript`
scroller.toLeft(1500);
Scroll animation to the specified Element.
Example:
`typescript`
scroller.toElement(document.getElementById('content'));
Will update the SweetScroll instance.
Primarily used in the case of option update.
Example:
`typescript`
scroller.update({
trigger: 'a[href^="#"]',
duration: 3000,
});
gotoEnd: {Boolean}
Will stop the current scroll animation.
Example:
`typescript`
scroller.stop(true);
Will destroy the SweetScroll instance.
Disable of the method and event handler.
Example:
`typescript`
scroller.destroy();
In before and after, you will pass the coordinates and the triggering element in the argument.before
In addition, you can stop the scrolling by return a in false.
Example:
`typescriptis-disabled
const scroller = new SweetScroll({
// Stop scrolling case of trigger element that contains the class.
before: (offset: Offset, $trigger: Element | null, scroller: SweetScroll): boolean | void => {
console.log('Before!!', offset, scroller);
if ($trigger && $trigger.classList.contains('is-disabled')) {
return false;
}
},
// If the wheel or touchstart event is called
cancel: (scroller: SweetScroll): void => {
console.log('Cancel!!', scroller);
},
// Scroll animation is complete
after: (offset: Offset, $trigger: Element | null, scroller: SweetScroll): void => {
console.log('After!!', offset, $trigger, scroller);
},
// Scroll animation is complete (after or cancel)
complete: (isCancel: boolean, scroller: SweetScroll): void => {
console.log('Complete!!', isCancel, scroller);
},
// Each animation frame
step: (time: number, scroller: SweetScroll): void => {
console.log('step', time, scroller);
},
});
`
Extends Class:
The following is a pattern to override a method in the inheritance destination class.
`typescript
import SweetScroll, { Offset } from 'sweet-scroll';
class MyScroll extends SweetScroll {
protected onBefore(offset: Offset, $trigger: Element | null): boolean | void {
// Stop scrolling case of trigger element that contains the is-disabled class.
console.log('Before!!', offset);
if ($trigger && $trigger.classList.contains('is-disabled')) {
return false;
}
}
protected onCancel(): void {
console.log('Canell!!');
}
protected onAfter(offset: Offset, $trigger: Element | null): void {
console.log('After!!', offset, $trigger);
}
protected onComplete(isCancel: boolean): void {
console.log('Complete!!', isCancel);
}
protected onStep(time: number): void {
console.log('step', time);
}
}
`
Works in IE10+, and all modern browsers.
It is necessary to use polyfill or ponyfill of requestAnimationFrame.
Example ponyfill
Using raf module.
`typescript
import raf from 'raf';
import SweetScroll from 'sweet-scroll';
SweetScroll.raf = raf;
SweetScroll.caf = raf.cancel;
`
See the CHANGELOG.md
1. Fork it!
1. Create your feature branch: git checkout -b my-new-featuregit commit -am 'Add some feature'
1. Commit your changes: git push origin my-new-feature
1. Push to the branch:
1. Submit a pull request :muscle:
Bugs, feature requests and comments are more than welcome in the issues.
We will develop using the following npm scripts.
#### yarn start
Launch the local server and let the demo run. Opening http://localhost:3000 in your browser.
#### yarn build
Compile TypeScript and create type definitions.
#### yarn test`
Run unit testing with Jest.