Intriguing animate-on-scroll effect – jQuery tutorial

23/08/11

I suppose that I was not the only one to become speechless in front of the Nizo for iPhone website.
In this tutorial we try to recreate the intriguing scrolling effect. We’ll go for simplicity : 5 objects to animate and linear movement, no easing. The basis that opens the door for further elaboration.

Click here to see the demo.
My herb garden preview

Download the source files

My herb garden
.zip 0.4MB

We’ll start with the html structure :

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>My herb garden</title>
</head>
<body>
<div id="wrap_out">
  <div id='wrap'>
    <header>
      <h1>My <em>herb</em> garden</h1>
      <p>Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum id ligula porta felis euismod semper.</p>
    </header>
    <div id="separation">
      <div>Scroll <em>down</em></div>
      <img src="images/herbes.jpg" width="592" height="350" alt="Herbes"> </div>
    <section>
      <div  id="coriander" class="element">
        <div>coriander</div>
        <img src="images/coriander1.jpg" width="286" height="232" alt="Coriander">
        <p>Cras mattis consectetur purus sit amet fermentum. Cras mattis consectetur purus sit amet fermentum. Cras mattis consectetur purus sit amet fermentum.</p>
      </div>
      <div  id="rosemary" class="element">...</div>
      <div  id="lemonbalm" class="element">...</div>
      <div  id="chives" class="element">...</div>
      <div  id="basil" class="element">...</div>
    </section>
    <footer> <a href="http://pehaa.com"> by <em>PeHaa</em> 2011</a> </footer>
  </div>
</div>
</body>
</html>

The document is composed of 4 elements header, #separation, section and footer, contained within two divs : #wrap_out and #wrap.
The stylesheet begins with a simple css reset and the @font-face declaration

body, div, h1, h2, form, fieldset, input, textarea, footer, p, img {
	margin: 0; padding: 0; border: 0; outline: none;
}
a { text-decoration:none; color: #fff;}

 @font-face {
 font-family: 'DeibiRegular';
 src: url('deibi-webfont.eot');
 src: url('deibi-webfont.eot?#iefix') format('embedded-opentype'),  url('deibi-webfont.woff') format('woff'),  url('deibi-webfont.ttf') format('truetype'),  url('deibi-webfont.svg#DeibiRegular') format('svg');
 font-weight: normal;
 font-style: normal;
}

Right now, the important point is to set width : 100% and overflow-x: hidden for the #wrap_out. The #wrap element centers the content of the page.
section is positioned relatively and the animated herbs (class="element") are positioned absolutely.
Let’s continue with our stylesheet :

body { 
	font-family:'DeibiRegular', Helvetica, Arial, sans-serif;
	background:#f2f2f2 url('images/bg.jpg');
	color: #fff; width:100%;
}
#wrap_out {width:100%; overflow-x:hidden;}
#wrap {width: 960px; margin: 0 auto; z-index:1;position:relative;}


header {display:block;z-index:2 position:relative;}
header p {display:block; font-size:30px; padding: 70px 60px 0px;}
h1 {text-align:center;font-size:130px; margin-top: 30px; text-shadow: 0 0 60px #889473;}
h1 em {color: #f5f187;font-style: normal;}

#separation {margin: 0 auto;width: 592px;z-index:-1;position:relative;}

section {position:relative; margin-top: 120px;display:block}

.element { position:absolute; display:block;}
.element#coriander {top:0px; left:30px; width: 286px; height: 272px;}
.element#rosemary {top:40px; left: 335px; width: 370px; height: 183px;}
.element#chives {top : 0px; right:30px; width: 197px; height: 514px;}
.element#lemonbalm {left: 30px; top:280px; width:265px; height: 233px;}
.element#basil {right: 255px; top:250px; width:368px; height: 263px;}

footer {margin-bottom: 10px;text-align:center;font-size: 30px; display:block}

The idea is to encourage the visitor to scroll down by positioning the #separation element at the bottom of the page. We want the #separation to stay there when the window is resized but to move up when we start to scroll down. A possible way to do that is to make the height of the header element dependent on the height of the window browser :

$(document).ready(function () {
    var myHeight;

    function init() {
        myHeight = $(window).height();
        $('header').css('height', myHeight - 300);
    }
    init();
    $(window).resize(function () {
        init();

    });
})

To animate the .element we’ll go simple and use a linear function to move it from its initial position to its target position. We assign four parameters (its initial and final coordinates) to each element :

$('.element').each(function(i) {
			var myElement =$(this);
			
			
				switch (i)
				{ case 0 : 
					myElement.data('params', {top0 : -1300, x0 : -2600, top1: $(this).css('top'), x1: $(this).css('left')}); 
					break; 
				case 1 : 
					myElement.data('params', {top0 : 0, x0 : -930, top1: $(this).css('top'), x1: $(this).css('left')}); 
					break; 
				case 2 : 
					myElement.data('params', {top0 : 280, x0 : -1030, top1: $(this).css('top'), x1: $(this).css('left')});
					break; 	
				 case 3 : 
					myElement.data('params', {top0 : -1200, x0 : -2330, top1: $(this).css('top'), x1: $(this).css('right')}); 
					break; 
				case 4 : 
					myElement.data('params', {top0 : 250, x0 : -530, top1: $(this).css('top'), x1: $(this).css('right')}); 
					break; 
				}
			});

What happens when we scroll ? The top property of each element and the left (for coriander, rosemary and lemon bald) or right (for chives and basil) changes as a function of the scroll position :

 
$(window).scroll(function () {
var s_max = myHeight / 2 + 500;
    function move(p0, p1, s) {
        return Math.min((-p0 + p1) / s_max * s + p0, p1);
    }
	
    var scrollTop = parseInt($(window).scrollTop());
    $('.element').each(function (i) {
       

        var myX = move($(this).data('params').x0, parseInt($(this).data('params').x1), scrollTop),
            myY = move($(this).data('params').top0, parseInt($(this).data('params').top1), scrollTop);
        
if (i < 3) {
            $(this).stop().css({
                left: myX + 'px',
                top: myY + 'px'
            })
        } else {
            $(this).stop().css({
                right: myX + 'px',
                top: myY + 'px'
            })
        }
    })
})

move is a function of the scroll value and has two parameters : initial (p0) and final (p1) position of an element.
Before we start scrolling, s = 0, move is equeal to p0. When scroll reaches s_max, the value of move is p1. The min operator prevents further movement.
As I said this is one of the simplest possible solutions.
What is s_max ? I wanted the animation to finish once the elements are verticaly centered in the middle of the window (I’m not pixel perfect here).
Where is that point ? Imagine that we don’t animate our elements and that they are in their final positions. Notice that we have to scroll down 500px (see the scheme below), to see the top of the second row of our herbs. If we scroll down a half height of a window more we will see them in the middle.
My herb garden preview
We want to be sure that the page is high enough so that the elements could reach their final positions. To assure that we will make the property height of section dependent on the height of the browser window, in this case we need to scroll $(window).height/2 + 500. We have 240px above the section (120px + 120px). The minimum height of section is then $(window).height/2 + 260. We add a line to the init function

function init() {
    myHeight = $(window).height();
    $('header').css('height', myHeight - 300);
    $('section').css('min-height', Math.max(myHeight / 2 + 260, 600));
}

It was tested in Safari, Firefox, Chrome, Opera, IE7 and IE8. It works in the last two if you don’t forget to add

<!--[if IE]>
	<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

I hope you find it useful. Please bookmark and share.
Let me know what you think – I’m looking forward to your comments. Thanks.

23 Responses to “Intriguing animate-on-scroll effect – jQuery tutorial”

  1. Design Social Media

    Aug 23rd, 2011

    nice jquery effect, thanks for the tut.

  2. Kimanh

    Aug 24th, 2011

    This is very cool. I’m going to try using this. Fingers crossed I can do it.

  3. pinkonhead

    Aug 24th, 2011

    Really cool effect, grat tut sister :)

  4. Noury Janse

    Aug 26th, 2011

    Looks nice! Especially when using the scrollbar manually with the mouse. The objects move very smooth :) !

  5. Phong Thai

    Sep 1st, 2011

    great job, but I think you should add scroll effect for clicking on “Scroll Down”

  6. Free Web Elements

    Sep 8th, 2011

    Great tutorial thanks !

  7. Sagar Ranpise

    Sep 15th, 2011

    Nice Tutorial and beautiful blog!

  8. juljan

    Oct 12th, 2011

    thanks great tutorial!

  9. lafeeeee

    Jan 11th, 2012

    that’s amazing.
    so cool.
    thanks very much

  10. Jorge Suárez

    Jan 12th, 2012

    Great tutorial thanks !

  11. Fantastic tutorial! Great work and yes, thank you for sharing!

  12. Dutchesz

    Mar 2nd, 2012

    Can’t wait to try it out :) Love your blog :)

  13. Bruno Cavenaghi

    Apr 24th, 2012

    PeHaa, great tutorial… i made some changes in your script to make more objects to animate in a larger height page.

    If you want, please visit my portfolio: http://www.brunocavenaghi.com

    Thanks, you helped a lot.

    See you

    • PeHaa

      Apr 24th, 2012

      Thanks ! I’ve just visited your portfolio. Impressive – love it. Glad I could have helped.

  14. Praveen

    Jun 21st, 2012

    so cool tnx pehaa :)

  15. emre

    Nov 14th, 2012

    thanks..good job….
    How can we change the speed of the animation?

  16. charis

    Aug 19th, 2013

    Hi there

    Great tutorial. I have been looking for this exact effect for weeks.

    I first saw this effect on this themify wordpress template http://themify.me/demo/#theme=parallax

    The effect is the same, but the elements also fade in as they animate into the screen

    I have been trying to get the same effect working, but to no avail.

    If you have time it would be a great update to this tutorial, adding fade in fade out

    Keep up the good work

  17. Jewel

    Oct 2nd, 2013

    Many thanks ….. well done.You helped a lot.

  18. Dani

    Nov 14th, 2013

    Hi, awesome post! I could not much info about this topic until I found it.

    I worked a bit in the function to make it possible that not all the elements stop at the same time, but in couple for example, when you scroll down. I have explained how I do it in my new blog :)

    http://danielrodriguezweb.wordpress.com/2013/11/11/my-website-scrolling-effects/

  19. Silvia

    Jan 28th, 2014

    It is GENIAL!!!!! Thanks a lot, I was looking for something like this!!

  20. Janice

    Jan 29th, 2014

    I’m not super familiar with javascript, is there a way to easily reverse this so that the objects are together when the page loads and then move off the screen as you scroll down?

  21. John

    Feb 9th, 2014

    Thanks for the tutorial. I happened to come across another jQuery script that does something similar.
    http://creativelycoded.com/2014/02/cre-animate-js-onscroll-animations/

Leave a Reply