Created
August 17, 2015 11:34
-
-
Save adrianspacely/1db9d96ace9813f04fdb to your computer and use it in GitHub Desktop.
Simple parallax background effect.
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
// Simple parallax background effect by Adrian Brown | |
// | |
// Example HTML: | |
// <div class="parallax fullscreen" | |
// style="background-image: url(example.jpg);" | |
// data-img-width="1280" | |
// data-img-height="800" | |
// data-difference="100"> | |
// </div> | |
// | |
// Requires jQuery. | |
var lastTime, | |
ticking, | |
scrolling, | |
resizing, | |
bypassHeightCheck, | |
bypassScrollCheck, | |
isTouch, | |
lastWindowW, | |
lastWindowH, | |
lastScrollY, | |
headerH; // This example is presuming there is a fixed <header> tag | |
// Resize background image on parallax elements | |
function backgroundResize() { | |
var windowH = lastWindowH, | |
fullscreenH = windowH - headerH, | |
threeQtrH = (windowH * 0.7) - headerH; | |
$(".parallax").each(function() { | |
var section = $(this), | |
imgW = section.attr("data-img-width"), | |
imgH = section.attr("data-img-height"), | |
conW = section.width(), | |
conH = section.height(), | |
ratio = imgW / imgH, // Width is always 100% | |
diff = parseFloat(section.attr("data-difference")), | |
remainingH = 0; | |
// Parallax distance (difference needed in image size) | |
diff = diff ? diff : 0; | |
// Resize section | |
section.css('max-height', fullscreenH); // Make sure height is less than viewport | |
if (section.hasClass('fullscreen')) { section.css("height", fullscreenH); } | |
if (section.hasClass('threeqtr')) { section.css("height", threeQtrH); } | |
// Remaining height to have fullscreen image only on parallax | |
if (!isTouch) { remainingH = windowH - conH; } | |
// Set img values depending on cont | |
imgH = conH + remainingH + diff; | |
imgW = imgH * ratio; | |
// Fix when too large | |
if (conW > imgW) { | |
imgW = conW; | |
imgH = imgW / ratio; | |
} | |
section.data("newheight", imgH); // Will need this for the parallax | |
section.css("background-size", imgW + "px " + imgH + "px"); | |
}); | |
} | |
// Run effect on all .parallax elements in view | |
function parallaxPosition() { | |
var windowH = lastWindowH, | |
scrollY = lastScrollY, | |
windowBottom = scrollY + windowH, | |
windowCurrent = (scrollY + windowBottom) / 2; | |
$(".parallax").each(function() { | |
var section = $(this), | |
height = section.height(), | |
top = section.offset().top, | |
bottom = top + height, | |
inView = scrollY < bottom && windowBottom > top; | |
if (inView) { | |
var imgH = section.data("newheight"), | |
min = 0, | |
max = - imgH + windowH, | |
overflowH = height < windowH ? imgH - height : imgH - windowH; | |
top = top - overflowH; | |
bottom = bottom + overflowH; | |
// Parallax value | |
var value = min + (max - min) * (windowCurrent - top) / (bottom - top); | |
// Set background-position | |
var horizontalAlign = "50%"; // Center align (default) | |
if (section.hasClass('left')) { horizontalAlign = "0%"; } // Left align | |
if (section.hasClass('right')) { horizontalAlign = "100%"; } // Right align | |
// Update background position | |
section.css("background-position", horizontalAlign + " " + value + "px"); | |
} | |
}); | |
} | |
// Flag all updates to occur on next update. Request's an update by default. | |
function flagForFullUpdate(trigger) { | |
trigger = typeof trigger !== 'undefined' ? !!trigger : true; | |
resizing = true; | |
scrolling = true; | |
bypassHeightCheck = true; | |
bypassScrollCheck = true; | |
if (trigger) { requestUpdate(); } | |
} | |
// Run an update | |
function update() { | |
if (resizing) { | |
var windowW = $(window).width(); | |
var windowH = $(window).height(); | |
if (windowW !== lastWindowW || windowH !== lastWindowH || bypassHeightCheck) { | |
if (windowH !== lastWindowH) { | |
flagForFullUpdate(false); // Need to update parallax bg y-position | |
} | |
lastWindowW = windowW; | |
lastWindowH = windowH; | |
backgroundResize(); | |
} | |
} | |
if (scrolling) { | |
var scrollY = $(window).scrollTop(); | |
if (scrollY !== lastScrollY || bypassScrollCheck) { | |
lastScrollY = scrollY; | |
if (!isTouch) { parallaxPosition(); } | |
} | |
} | |
// Update has finished, allow for further updates. | |
bypassHeightCheck = false; | |
bypassScrollCheck = false; | |
scrolling = false; | |
resizing = false; | |
ticking = false; | |
} | |
// Request an update | |
function requestUpdate() { | |
if (!ticking) { | |
window.requestAnimationFrame(update); // Seems to run smoother using this | |
ticking = true; // Prevent further updates | |
} | |
} | |
// Init | |
function initParallax() { | |
// Instantiate variables | |
ticking = false; | |
scrolling = false; | |
resizing = false; | |
bypassHeightCheck = false; | |
bypassScrollCheck = false; | |
isTouch = "ontouchstart" in window; | |
lastWindowW = $(window).width(); | |
lastWindowH = $(window).height(); | |
lastScrollY = $(window).scrollTop(); | |
headerH = $("header").outerHeight(); | |
// Enable parallax | |
if (!isTouch) { $(".parallax").each(function() { $(this).css("background-attachment", "fixed"); }); } | |
// requestAnimationFrame() support | |
if (!window.requestAnimationFrame) { | |
lastTime = 0; | |
window.requestAnimationFrame = function(callback, element) { | |
var currTime = new Date().getTime(); | |
var timeToCall = Math.max(0, 16 - (currTime - lastTime)); | |
var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); | |
lastTime = currTime + timeToCall; | |
return id; | |
}; | |
} | |
// Start | |
flagForFullUpdate(); | |
} | |
// Scroll function | |
function onScroll() { | |
scrolling = true; | |
requestUpdate(); | |
} | |
// Resize function | |
function onResize() { | |
resizing = true; | |
requestUpdate(); | |
} | |
// Event handlers | |
window.addEventListener('scroll', onScroll, false); | |
window.addEventListener('resize', onResize, false); | |
// Run the code | |
$(function() { initParallax(); }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment