Our Blog

On scroll animations using waypoints.js and animate.css

by Harris Konstantourakis on July 31, 2014 31 comments

Did you ever wonder how the best themes implement on scroll animations? This tutorial will allow you to recreate the effect using the popular jquery-waypoints plugin as well as the animate.css library.

On scroll animation is a technique which has gained popularity over the past several months. It suits one-page websites as well as websites with many illustrations perfectly, giving them a more dynamic appearance. However, the animations can be applied to any element as we will soon see.

For this tutorial we assume the reader has some prior experience with javascript and more specifically with the jQuery library, as we will need the aid of the popular jQuery-waypoints plugin. Waypoints is a plugin that allows us to easily execute a function whenever we scroll to an element.

The following example will alert the user when he scrolls on any element that has a class ‘notify’:

$('.notify').waypoint(function(direction) {
  alert('Top of notify element hit top of viewport.');

One can pass a second argument to the waypoint function, which is an options object. An option of interest for us today is the offset option, which tells Waypoints how far from the top of the window the callback function should fire.

$('.notify').waypoint(function(direction) {
  alert('Top of notify element hit top of viewport.');

In the example above we express the offset as a percentage of the viewport’s height.

Having a solid grasp of how Waypoints work, we can now move on to Daniel Eden’s animate.css library. animate.css is a bunch of cool fun and cross-browser animations that we can use in our projects.

Grab a copy of the stylesheet and include it in your project. After that you will be able to animate your elements by simply adding the class animated to them, along with the name of the specific animation you want to apply.We will use jQuery to add the animation classes to our elements.The following code illustrates how this can be achieved:

$('.toBeAnimated').addClass('animated fadeInLeft');

The above code will make all elements that have a class toBeAnimated to animate

animate.css also let’s us modify the duration of our animations and add a delay which can come in handy.

.toBeAnimated {
  -vendor-animation-duration: 3s;
  -vendor-animation-delay: 2s;

The above style will trigger an animation that lasts 3 seconds, 2 seconds after the class animated is applied to an element.

The best way to define the animations (or behaviours in general) for an element would be through data attributes.We will use data attributes to specify what type of animations our elements will perform, as well as possible delays in the animation. Here is what the markup for an animated section will look like:

<section class="os-animation" data-os-animation="swing" data-os-animation-delay="0s">
    <h1>This section will swing</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>

Studying the snipped above, one will notice that we added a class os-animation to our section. That will help us target this as well as other sections with the same class through jQuery. The two data attributes specify the animation we want the section to perform, as well as the delay (no delay in this case).

Wouldn’t it be great if our section was initially hidden and only appeared when it scrolled into view and animated? Let’s add some css that will help us accomplish exactly that:

  opacity: 0;

    opacity: 1;

It is now time to combine the two concepts we saw earlier and create a small script that will handle the animation of our elements once they come into view. Without further ado:

function onScrollInit( items, trigger ) {
  items.each( function() {
    var osElement = $(this),
        osAnimationClass = osElement.attr('data-os-animation'),
        osAnimationDelay = osElement.attr('data-os-animation-delay');

        '-webkit-animation-delay':  osAnimationDelay,
        '-moz-animation-delay':     osAnimationDelay,
        'animation-delay':          osAnimationDelay

    var osTrigger = ( trigger ) ? trigger : osElement;

    osTrigger.waypoint(function() {
        triggerOnce: true,
        offset: '90%'

The above function expects two arguments, the second being optional. A list of items that we want to animate, and an optional container in case we want to perform staggered animations. For each of those elements, we extract the animation information from their data attributes, and animate them once they appear at the bottom of our viewport. Notice that we added the triggerOnce option in our options object since we want each element to animate only once, when it comes into our view as we scroll.

Calling the above function once the document has loaded with the following code:

 onScrollInit( $('.os-animation') );

will animate our previous section as well as other sections with the same class and similar data attributes once they come into our view.

But what if I want staggered animations? An animation is called staggered when it contains a delay between each successive animation. You have most probably seen it in websites that animate paragraphs that belong in the same section in ‘layers’. Let’s see how we can use our previous function in order to achieve that as well. Create a section in your body of your html document that looks like this:

<section class="staggered-animation-container">
    <h1>This section contains staggered animations!</h1>
    <p class="staggered-animation" data-os-animation="fadeInRight" data-os-animation-delay="0.5s">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
    <p class="staggered-animation" data-os-animation="fadeInRight" data-os-animation-delay="0.8s">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
    <p class="staggered-animation" data-os-animation="fadeInRight" data-os-animation-delay="1.1s">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>

In the above code you will notice that we apply the animation attributes to the paragraphs inside the section, which all have the same class staggered-animation and we add a staggered-animation-container class to the section that contains them. The idea this time is to trigger the waypoint callback once the section is at the bottom of our view, and have the paragraphs inside animate in layers.Thus we will call our function this time like this:

onScrollInit( $('.staggered-animation'), $('.staggered-animation-container') );

This time we passed a second argument to the function as well. The first argument is the selector for the elements we want to animate, and the second is for their container that will trigger the animations once it scrolls into view. Notice in the markup that we needed different (incemental) delays for each item inside the container in order to achieve the effect.

Harris KonstantourakisOn scroll animations using waypoints.js and animate.css

Related Posts

Take a look at these posts


Join the conversation
  • langan - July 31, 2014 reply

    Nice article Roulis!

  • alexander - July 31, 2014 reply

    a very cool post thx

    Damien - October 16, 2015 reply

    great info Thanks for the marvelous potisng! I genuinely enjoyed reading it, you’re a great author.I will remember to bookmark your blog and definitely will come back down the road. I want to encourage one to continue your great work, have a nice day!

  • Aaron O. - April 16, 2015 reply

    This is a great tutorial, and I used it on a few projects so far. The only modification I made was to add an onscroll event on window to trigger the onScrollInit() function. I did this because when the page loads, and if images, or other elements aren’t loaded, it throws off the offset and the animation loads before hitting the offset. So, before the onScrollInit function declaration, I added a variable called scrolling and set it to false. Then I wrapped the onScrollInit function in a on scroll event. If you need the animation to load like on a header, then it may be usefull to add another data-attribute to the animated element, something like data-animation-scroll=”false”, then use that conditional to control the window.on.scroll event.

    // Heres what I ended up doing
    var scrolling = false;
    function onScrollInit( items, trigger){
    // code from above

    $(window).on(‘scroll’, function(){
    onScrollInit( $(‘.os-animation’) );
    scrolling = true;

    Adrian M - April 21, 2015 reply

    Great article and thanks Aaron for the input, helped me out bud!

    aneesa - July 7, 2015 reply

    can you send me a link to a preview?

    Melania - October 16, 2015 reply

    Very nice post. I just stumbled upon your wlebog and wanted to say that I’ve truly enjoyed browsing your blog posts. In any case I will be subscribing to your feed and I hope you write again very soon! Howdy!

    Fabio - December 14, 2015

    Thanks for sharing. I will have to ttarslane the site from Japanese, but I like what they are doing. Looks like they have an unscannable animation intro, and then it rotates the same loop.I wonder if its automated like the other generators, or hand built?Looks like I have a lot to learn on this subject still.best,pd

    Mike - May 8, 2015 reply

    Great tip Aaron, I was stumped till you shed some light on it! Thanks man! Great article too by the way. I owe some of yall a beer!

  • Adam - April 28, 2015 reply

    Good information on “On scroll animation technique”.Thanks!

    Panita - October 16, 2015 reply

    Ryan Lamont I blog frequently and I geulineny thank you for your information. The article has truly peaked my interest. I’m going to take a note of your site and keep checking for new details about once per week. I subscribed to your Feed too .

  • Subhasish - July 3, 2015 reply

    Nice! Helped me out in my project , thanks a lot.

    Dimitrios Pantazis - July 14, 2015 reply

    Glad you liked them!

  • Anja - August 14, 2015 reply

    Exactly what I was looking for! THANKS!!!

  • Her - October 7, 2015 reply

    Great! But how can i make the animation repeats when scroll back, and not only for the first scrolling? Thanks!

    Harris Konstantourakis - October 8, 2015 reply

    You probably want to remove the “triggerOnce: true” option in your case!

    Her - October 8, 2015 reply

    I try this but notting happens!

  • Christian - October 13, 2015 reply

    Nevermind.. I guess you need a different class for the trigger.

  • Pieter E. - January 9, 2016 reply

    I love this blog and solution. Thank you for explaining!

    I’d like to upgrade waypoints and animate.css to the latest versions. I tried the latest version of waypoints v4.0.0 (instead of v2.0.4) and animate.css v3.5.0 (instead of v3.1.0) on the code above. This doesn’t work, the animations aren’t triggered. Is there someone who tried the same and found already a solution? Thank you in advance for sharing. 🙂

  • sunil - January 14, 2016 reply

    Thanks ! Great Article…..

  • Scott - January 26, 2016 reply

    Your method is beautiful. Thank you for sharing.

  • Tim - March 7, 2016 reply

    Great post, thanks for sharing. I have this working on my site, but if I have multiple trigger elements with the same class then they all fire when I reach the first one on the page instead of each firing as I scroll to them. I’ve tried adding an trigger.each(function() around the items.each(function() but haven’t had any success. Any thoughts?

    Harris Konstantourakis - November 24, 2017 reply

    Hi Tim,

    apologies for such a late reply, I am commenting on this in case others come across a similar issue. The second argument ( trigger ) in the function is to be used when one wants to ‘group’ animations.

    Your use case is different, you have some items that you want to animate once they come into view, and all the items have the same class. Let’s say that the class is ‘toBeAnimated’ .

    What you have to do is call onScrollInit( $(‘.toBeAnimated’) ); once. No second argument should be applied to the function.

    Hope that clears some things up!

  • dinh - October 24, 2016 reply

    Thank god

    christos - December 11, 2016 reply

    Glad you liked it 😉

  • Kelyn - December 22, 2016 reply

    Ohh Thank you so much! , I’ve been searching for something like that for days, it was implemented in my project and works perfectly. Thanks for sharing 🙂

  • VideoPortal - March 24, 2017 reply

    Nice tutorial. I am trying to animate a element so that when the element scrolls into view it s width grows from x to 1x and back to 1x. I have managed to get this to work using animation keyframes but the animation only works on page load is this possible to do?

  • zillo9w.com - June 1, 2017 reply

    Simon Codrington explains how to use jQuery and CSS3 to add scroll-based animations to your site and thereby offer your users a more engaging experience.

  • Roee yossef - June 6, 2017 reply

    Thanks for the great solution.

    This works on one “staggered-animation-container”.. what if i need to use different triggers on different elements on the page?

  • Asher Garland - July 15, 2017 reply

    Building on the information above, I created a dead-simple way to create on-scroll animations for your elements. Check it out here: https://github.com/ashergarland/easy-waypoint-animate

    christos - November 24, 2017 reply

    Thanks for sharing!

Join the conversation