Last active
August 14, 2017 13:58
-
-
Save guillaumepiot/8fd21410f5bbc40166e981f7b553d5fe to your computer and use it in GitHub Desktop.
parallax.js
This file contains 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
// For a given HTML snippet with the class "parallax" | |
// | |
// <div class="parallax" style="height: 400px; overflow: hidden;"> | |
// <div style="background-image:url('http://via.placeholder.com/1600x780');"></div> | |
// </div> | |
(function(){ | |
var speedRatio = 4 | |
var minYOffset = -200 | |
// All parallaxable elements on the page will be registered here | |
var parallaxElms = [] | |
function scrollHandler () { | |
var winHeight = window.innerHeight | |
var scrollY = window.scrollY | |
parallaxElms.forEach(function (elm) { | |
// Get the position of the image container relatively to the page viewport | |
var r = elm['elm'].getBoundingClientRect() | |
elmTop = r.top | |
elmBottom = r.bottom | |
elmHeight = r.height | |
// Calculate the amount of translation available based in the height | |
// of the image minus the height of the image container | |
var translatableRange = elm.imageHeight - elmHeight | |
// Prevent the parallaxing effect when the image container if off screen | |
if (elmTop > winHeight) { | |
return | |
} | |
if (elmBottom < 0) { | |
return | |
} | |
// Calculate the negative percentage of the container position in | |
// relation to the view port. When the top of the image container | |
// appears at the bottom of the page, it's 100%. When the bottom of the | |
// image container go over the top of the page, it's 0%. | |
var perc = (elmBottom / (winHeight + elmHeight)) | |
// Workout the translation amount to do based on the percentage of | |
// travel of the image container from the bottom to the top of the page | |
var y = - (perc * translatableRange) | |
// Apply the transation the inner div containing the actual image | |
elm['elm'].children[0].style.transform = "translate3d(0px, "+ y +"px, 0px)"; | |
}) | |
} | |
function initParallax () { | |
var elms = document.querySelectorAll('.parallax') | |
var numOfThings = elms.length | |
var currentThings = 0 | |
// Create a function that counts the amount of callback it expects to | |
// receive, only call the final function when all have returned. | |
function callback() { | |
currentThings++ | |
if (currentThings === numOfThings) { | |
resizeHandler() | |
} | |
} | |
// When we first load the page, measure the size of each background | |
// image | |
elms.forEach(function (elm) { | |
// Get the background image url from the element style | |
imageUrl = elm.children[0].style.backgroundImage.slice(5, -2) | |
img = new Image() | |
// Wait for the image to be loaded, then add its dimensions to the | |
// parallax elements array. | |
img.addEventListener('load', function(){ | |
parallaxElms.push({ | |
elm: elm, | |
imageOriginalHeight: this.height, | |
imageOriginalWidth: this.width, | |
}) | |
callback() | |
}) | |
// Assigning the image source will trigger the image load. | |
img.src = imageUrl | |
}) | |
document.addEventListener('scroll', scrollHandler) | |
window.addEventListener('resize', resizeHandler) | |
} | |
function resizeHandler () { | |
// Every time we resize the window, calculate the display height of | |
// the image in relation to the width of its container. That way, we always | |
// optimise the amount of scroll available. | |
parallaxElms.forEach(function (elm) { | |
containerWidth = elm.elm.offsetWidth | |
var ratio = containerWidth / elm.imageOriginalWidth | |
var imageDisplayHeight = elm.imageOriginalHeight * ratio | |
elm.imageHeight = imageDisplayHeight | |
elm.elm.children[0].style.height = imageDisplayHeight + 'px' | |
}) | |
scrollHandler() | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// Bootstrap any file uploaders | |
function documentReady () { | |
return (document.readyState === 'interactive' || document.readyState === 'complete') | |
} | |
function bootstrap () { | |
document.removeEventListener('readystatechange', bootstrap) | |
initParallax() | |
} | |
if (documentReady()) { | |
bootstrap() | |
} else { | |
document.addEventListener('readystatechange', bootstrap) | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment