Skip to content

Instantly share code, notes, and snippets.

@shuding
Created January 2, 2020 19:33
Show Gist options
  • Save shuding/3b229dbea28244b026f6f84c7264e985 to your computer and use it in GitHub Desktop.
Save shuding/3b229dbea28244b026f6f84c7264e985 to your computer and use it in GitHub Desktop.
SmoothScroll
// SmoothScroll
class SmoothScroll {
constructor() {
// the <main> element
this.DOM = {main: document.querySelector('main')};
// the scrollable element
// we translate this element when scrolling (y-axis)
this.DOM.scrollable = this.DOM.main.querySelector('div[data-scroll]');
// the items on the page
this.items = [];
this.DOM.content = this.DOM.main.querySelector('.block--story');
[...this.DOM.content.querySelectorAll('.block__item')].forEach(item => this.items.push(new Item(item)));
// here we define which property will change as we scroll the page
// in this case we will be translating on the y-axis
// we interpolate between the previous and current value to achieve the smooth scrolling effect
this.renderedStyles = {
translationY: {
// interpolated value
previous: 0,
// current value
current: 0,
// amount to interpolate
ease: 0.1,
// current value setter
// in this case the value of the translation will be the same like the document scroll
setValue: () => docScroll
}
};
// set the body's height
this.setSize();
// set the initial values
this.update();
// the <main> element's style needs to be modified
this.style();
// init/bind events
this.initEvents();
// start the render loop
requestAnimationFrame(() => this.render());
}
update() {
// sets the initial value (no interpolation) - translate the scroll value
for (const key in this.renderedStyles ) {
this.renderedStyles[key].current = this.renderedStyles[key].previous = this.renderedStyles[key].setValue();
}
// translate the scrollable element
this.layout();
}
layout() {
this.DOM.scrollable.style.transform = `translate3d(0,${-1*this.renderedStyles.translationY.previous}px,0)`;
}
setSize() {
// set the heigh of the body in order to keep the scrollbar on the page
body.style.height = `${this.DOM.scrollable.scrollHeight}px`;
}
style() {
// the <main> needs to "stick" to the screen and not scroll
// for that we set it to position fixed and overflow hidden
this.DOM.main.style.position = 'fixed';
this.DOM.main.style.width = this.DOM.main.style.height = '100%';
this.DOM.main.style.top = this.DOM.main.style.left = 0;
this.DOM.main.style.overflow = 'hidden';
}
initEvents() {
// on resize reset the body's height
window.addEventListener('resize', () => this.setSize());
}
render() {
// Get scrolling speed
// Update lastScroll
scrollingSpeed = Math.abs(docScroll - lastScroll);
lastScroll = docScroll;
// update the current and interpolated values
for (const key in this.renderedStyles ) {
this.renderedStyles[key].current = this.renderedStyles[key].setValue();
this.renderedStyles[key].previous = MathUtils.lerp(this.renderedStyles[key].previous, this.renderedStyles[key].current, this.renderedStyles[key].ease);
}
// and translate the scrollable element
this.layout();
// for every item
for (const item of this.items) {
// if the item is inside the viewport call it's render function
// this will update item's styles, based on the document scroll value and the item's position on the viewport
if ( item.isVisible ) {
if ( item.insideViewport ) {
item.render();
}
else {
item.insideViewport = true;
item.update();
}
}
else {
item.insideViewport = false;
}
}
// loop..
requestAnimationFrame(() => this.render());
}
}
@shuding
Copy link
Author

shuding commented Jan 2, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment