Reputation: 151
I have a custom parallax scrolling section of a site. There are speech bubbles in various places and they all scroll at different speeds.
http://goo.gl/jZhVrJ (you will find the speech bubbles half way down the page)
When you scroll down the first time, it all works fine and the elements are positioned where I would like them. Here is a screenshot of how it should look:
However, if you scroll back to the top, then back down again - the positioning of the bubbles is different every time you go back to that section. If you do it enough times you can get the speech bubbles completely outside that block of content. Here is a screenshot of it eventually not looking right:
The general concept here is that I have positioned each of the speech bubbles. Then, as the user scrolls the code changes the 'top' property for each bubble. If the user is scrolling down, it reduces the 'top' value. If they are scroll up, it increases the 'top' value. Each bubble is a different magnifier so the bubbles appear to be moving at different speeds.
This also uses the "inview" plugin so the scrolling only happens while the user has that block in view.
Here is the JS code doing the parallax scrolling:
var $window = $(window);
var windowHeight = $window.height();
var $quoteBG = $('.philosophy');
var quote1 = $("#quote1");
var quote2 = $("#quote2");
var quote3 = $("#quote3");
var quote4 = $("#quote4");
var quote5 = $("#quote5");
var quote6 = $("#quote6");
var quote7 = $("#quote7");
var quote8 = $("#quote8");
var quote9 = $("#quote9");
var scrolldirection = '-';
var lastScrollTop = 0;
var modifier = '-';
$(window).scroll(function(event){
var st = $(this).scrollTop();
if (st > lastScrollTop){
scrolldirection = 'down';
} else {
scrolldirection = 'up';
}
lastScrollTop = st;
});
//function to be called whenever the window is scrolled or resized
function Move(){
//if the second section is in view...
if($quoteBG.hasClass("inview")){
if ( scrolldirection == 'down' ) {
modifier = '-';
} else {
modifier = '+';
}
quote1.css( 'top', modifier+'=2');
quote2.css( 'top', modifier+'=1');
quote3.css( 'top', modifier+'=3');
quote4.css( 'top', modifier+'=2.1');
quote5.css( 'top', modifier+'=2.5');
quote6.css( 'top', modifier+'=3');
quote7.css( 'top', modifier+'=2');
quote8.css( 'top', modifier+'=1.5');
quote9.css( 'top', modifier+'=3');
}
}
$window.resize(function(){ //if the user resizes the window...
Move(); //move the background images in relation to the movement of the scrollbar
});
$window.bind('scroll', function(){ //when the user is scrolling...
Move(); //move the background images in relation to the movement of the scrollbar
});
Upvotes: 0
Views: 447
Reputation: 4453
I had to add the following code to your fiddle to get it working:
$quoteBG.on('inview', function (evt, isInView) {
if (isInView) {
$quoteBG.addClass("inview");
}
else {
$quoteBG.removeClass("inview");
}
});
The fixed version is here: http://jsfiddle.net/up15ns6t/2/
After playing with it, I see a couple issues.
First issue is what I suspected from the start: your position calculations are done by adding or subtracting a fixed amount each time a scroll event fires. The problem with this is that you are making the same adjustment regardless of how far the window was scrolled. For example, you are adjusting the first quote by 2 px when the window scrolls 1 pixel between events and when it scrolls 100 pixels between events. This makes the results non-deterministic.
If I were doing it, I'd try to come up with a deterministic algorithm that calculates the position of each quote based on the scroll position of the window. Alternatively, you could try using your add/subtract approach, but include in your calculations the amount that the window has scrolled since the last event.
The other thing I noticed while playing with it is that the position doesn't get updated when the parent div (.philosophy
) gets hidden. So if you keep scrolling it in and out of view, the quotes gradually creep up. This behavior is caused by this line of code:
if($quoteBG.hasClass("inview")){
You would need to include an "or was previously in view" case to that logic.
I don't have more time to play with it and come up with a working version at the moment, but maybe you can use these ideas to get it working.
Update 1
I created a simple deterministic algorithm in your fiddle and applied it to a single quote div to keep things from getting too confusing. It first calculates the amount of the background div that is visible:
var windowHeight = $window.height();
var backgroundTop = Math.round($quoteBG.offset().top);
var st = $window.scrollTop();
var visibleHeight = (windowHeight + st) - backgroundTop;
The visibleHeight
value will be negative if the background div is below the bottom of the view port. Once that becomes positive, I calculate the new position for the quote div based on that.
On page load, I recorded the initial position of the quote div and defined a motion ratio for it:
var motion1 = 0.5;
var baseTop1 = $quote1.position().top;
When scrolling, I use these combined with the visibleHeight
to calculate the position for the quote:
var position1 = baseTop1 + Math.round(visibleHeight * motion1)
So in this example, the quote scrolls down at half the speed of the background (due to motion1 = 0.5
).
The updated fiddle is here: http://jsfiddle.net/up15ns6t/5/
One thing to note is that the position calculation does not handle the case where the quote goes off the bottom of the background. If you wanted to put something below it, you might need to add some checking to prevent the quote from moving too far down.
Upvotes: 1