Skip to content

Instantly share code, notes, and snippets.

@ebinion
Created June 2, 2017 16:33
Show Gist options
  • Save ebinion/823146456affae1da49c7ac1add188ed to your computer and use it in GitHub Desktop.
Save ebinion/823146456affae1da49c7ac1add188ed to your computer and use it in GitHub Desktop.
/**
* Toggles a className on an element based on it's visiblity on screen
* @type {Class}
* @param {HTMLElement} element Element you'd like to toggle
* @param {Object} [options={}] Optional settings
*/
class ScrollToggle {
constructor(element, options={}) {
// Setup default options
const defaultOptions = {
className: 'is--visible',
padVisibility: 100
}
// Assign properties
this.element = element
this.options = Object.assign({}, defaultOptions, options)
// Use data attribute if available
if(this.element.getAttribute('data-scroll-toggle-class') !== '') {
this.options.className = this.element.getAttribute('data-scroll-toggle-class')
}
// This binding
this.addClass = this.addClass.bind(this)
this.getElementPosY = this.getElementPosY.bind(this)
this.getWindowPosY = this.getWindowPosY.bind(this)
this.isOnScreen = this.isOnScreen.bind(this)
// Eventlisteners
window.addEventListener('scroll', () => {
window.requestAnimationFrame(this.addClass)
})
// Initial call
this.addClass()
}
/**
* Adds this.options.className to element when visible on screen
*/
addClass() {
if(this.isOnScreen()) {
this.element.classList.add(this.options.className)
} else {
this.element.classList.remove(this.options.className)
}
}
/**
* Determines whether element is on screen based on scroll position
* @return {Boolean} True if element is visible on screen
*/
isOnScreen() {
const windowY = this.getWindowPosY()
const elementY = this.getElementPosY()
if(windowY.max >= elementY.min + this.options.padVisibility && windowY.min <= elementY.max - this.options.padVisibility) {
return true
} else {
return false
}
}
/**
* Gets the offsetTop of the window and end of visible area
* @return {Object} Object.min and Object.max properties define the visible coordinates
*/
getWindowPosY() {
return {
min: window.scrollY,
max: window.scrollY + window.innerHeight
}
}
/**
* Gets the offsetTop of this.element and end of its visible area
* @return {Object} Object.min and Object.max properties define the visible coordinates
*/
getElementPosY() {
const body = document.querySelector('body')
let offsetY = this.element.offsetTop
// Let's loop through offsetParents until we reach the body
let element = this.element
while (element.offsetParent !== body) {
offsetY += element.offsetParent.offsetTop
element = element.offsetParent
}
return {
min: offsetY,
max: offsetY + this.element.offsetHeight
}
}
}
export default ScrollToggle
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment