Created
January 2, 2020 19:33
-
-
Save shuding/3b229dbea28244b026f6f84c7264e985 to your computer and use it in GitHub Desktop.
SmoothScroll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Source: https://tympanus.net/codrops2019/js/demo.js