I am trying to make a parallax effect that only involves backgrounds and header/footer images, leaving alone the main content markup (a regular wordpress loop).
The backgrounds are all in the div #page
which takes the whole document, except for a top banner which is an img
in a separate div at the top, .site-branding
, and the fill background which is in body
.
#page {
background:url("http://i.imgur.com/jK3tbU8.png") no-repeat scroll bottom center, url("http://i.imgur.com/TSrLfq1.png") repeat-x scroll top center, url("http://i.imgur.com/Md0r0mw.png")repeat-x scroll bottom center;
padding:0;
margin:0;
transition: 0s ease-in-out;
transition-property: background-position;
}
body {
background:url("http://i.imgur.com/910XVzz.jpg") repeat scroll top;
padding:0;
margin:0;
transition: 0s ease-in-out;
transition-property: background-position;
}
.site-branding {
margin-left:auto;
margin-right:auto;
min-width: 0;
overflow: hidden;
display: block;
}
.site-branding img {
max-width:100%;
margin-left:0;
}
The top banner scrolls up at a certain speed, the top background scrolls up at a slightly slower pace, the fill scrolls normally in the middle of the page...
So far so good (please refer to the JSFiddle linked below to follow all of this a little more conveniently).
I then want to make the two bottom backgrounds, jK3tbU8.png
and Md0r0mw.png
, to scroll up at their own speed (for example, slower than scroll), eventually stopping at the bottom of the page (jK3tbU8.png
is a "mandala" footer banner, which is on top of jK3tbU8.png
, the bottom fade background).
With the script below I can make them come up at their own speed: but I cannot make them stop exactly at the bottom.
I think this might happen mainly because scrollTop()
and offset()
are all based on top...?
You would think it is only a matter of subtracting values, but I find that the height of the viewport of course makes all the difference. If the viewport changes, the images end at a higher or lower position, although with very small differences.
I guess I need to factor the viewport in the calculation? but I don't know how!
Here's my whole code, I put a lot of comments in it, hopefully it will be not too difficult to understand:
jQuery(function ($) {
"use strict";
$(document).ready(function(){
var $win = $(window);
$('div#page').each(function(){
//set an arbitrary "speed"
var scroll_speed1 = 8;
var viewportHeight = $(window).height();
//set heights of backgrounds (any easy way to get this dynamically?)
var topFade = 600;
var bottomFade = 870;
var mandalaBottom = 457;
var $this = $(this);
//set background-attachment here, so that in style.css top-fade can be "scroll"
//needed in case the script breaks
$this.css("background-attachment", "scroll, fixed, scroll");
//set all the initial positions
//the idea is that if the images are down below (= higher number)
//they will scroll up faster, at a matching speed (= number dimishing faster)
var bgP1 = ( ($this.outerHeight()*2) + mandalaBottom ); //mandala-bottom
var bgP2 = $this.offset().top; //top-fade
var bgP3 = ($this.outerHeight()+(bottomFade)); //bottom-fade
var initialValue = "center " + bgP1 + "px," + "center " + bgP2 + "px," + "center " + bgP3 + "px";
//put the images in the css
$this.css("background-position", initialValue);
//bind to the scroll event
$(window).scroll(function() {
//percent between viewport and height of page
var viewportDiff = percentChange($this.outerHeight(), viewportHeight);
console.log("the percent between viewport and height of page is: " + viewportDiff+ "%");
//percent between position of pic and height of page
var perDiff = percentChange(bgP1, $this.outerHeight());
console.log("the percent between position of pic and height of page is: " + perDiff);
/* 1) $win.scrollTop() = position of the scroll (increasing number)
2) perDiff = the proportion between the page and the position of the pic (%)
3) viewportDiff= the proportion between the page and the viewport (%)
4) $this.outerHeight() = height of the page
=> scroll + the x% of scroll (given by the difference with the position of the pic) - the x% of page (given by the difference between viewport and page) + the height of the image */
var numberToSubstract = ( $win.scrollTop() + percentOf($win.scrollTop(), perDiff) - percentOf(viewportDiff, $this.outerHeight() ) + (mandalaBottom/2) );
console.log("the initial position of the pic was: " + bgP1);
console.log("we have substracted this much: " + numberToSubstract);
var bgNP1 = bgP1 - numberToSubstract - (mandalaBottom);
console.log("the pic now is here: " + bgNP1);
console.log("the height of the page is: " + $this.outerHeight());
//this calculates where to put the top-fade as the page is scrolled
var bgNP2 = -(($win.scrollTop() - $this.offset().top)/ scroll_speed1);
//this calculates where to put the bottom-fade as the page is scrolled
var perDiff3 = percentDiff(bgP3, $this.outerHeight());
var numberToSubstract3 = ($win.scrollTop() + percentOf($win.scrollTop(), perDiff3)) / scroll_speed1;
var bgNP3 = bgP3 - numberToSubstract3 - bottomFade;
//put the new values in the css
var newValue = "center " + bgNP1 + "px," + "center " + bgNP2 + "px," + "center " + bgNP3 + "px";
$this.css("background-position", newValue);
}); //scroll
}); //page
//this takes care of mandala-top
$('div.site-branding').each(function(){
//set an arbitrary speed
var scroll_speed = 1.5;
//bind to the scroll event (again?)
$(window).scroll(function() {
//this calculates where to put the top-fade as the page is scrolled
var bgNP2 = -( ($win.scrollTop() /*- $this.offset().top --not needed since it is 0*/) / scroll_speed );
//put the new values in the css
var newValue2 = bgNP2 + "px";
$('#mandalaTop').css("position", "relative");
$('#mandalaTop').css("top", newValue2);
$('#mandalaTop').height(448 /*height of top img*/);
}); //scroll
}); //div.site-branding
});//document ready
if(navigator.userAgent.match(/Trident\/7\./)) {
$('body').on("mousewheel", function () {
event.preventDefault();
var wd = event.wheelDelta;
var csp = window.pageYOffset;
window.scrollTo(0, csp - wd);
});
}
//following this calculation:
//http://www.calculatorsoup.com/calculators/algebra/percent-difference-calculator.php
function percentDiff(val1, val2) {
var difference = ( (val1 - val2) / ((val1+val2) / 2) ) * 100;
return difference;
}
function percentOf(percent, value) {
var n = percent/100;
return n * value;
}
function percentChange(bigVal, smallVal) {
var change = ( (smallVal-bigVal) / bigVal ) * 100;
return 100 + change;
}
});
To understand the above a little better, and see the simple html markup which contains all this, here's a JSFiddle.
It works as it should, which means, everything is fine at the top, but messed up at the bottom.