Creating movement is great way to provide an interesting and interactive experience for your viewers. With modern sites providing a greater deal of interactivity, it’s becoming increasingly expected that even simple websites will offer some level of animation / movement to engage their visitors.

Today I will be outlining a technique that you can adapt to your web projects – triggering animations when scrolling into a pre-defined region. These animations will be created using CSS transforms and CSS transitions. We will also use jQuery to detect when the elements are visible and to add/remove the appropriate classes.

For those who want to see examples of this in action, you can jump straight to the demos.

Why Trigger Animations on Scroll?

The main reason we would want to trigger animations on scroll, is so that they activate just as the user scrolls an element into view.

We might want to fade elements in, or provide an interesting transformation and these would only make sense when the user can actually view them.

Animating with CSS or with jQuery?

There are pros and cons to each approach. jQuery (read JavaScript) allows you to animate things that CSS doesn’t (such as the scroll position, or an element’s attributes), whilst CSS animations can be very attractive for developers who prefer putting all of their animation and presentation logic in the CSS layer.

I will be using transformations via CSS, however there are always variables to consider depending on your situation. I would take the following factors into account:

Browser Compatibility

Since our solution will be based on transformations, our browser compatibility will be limited to those that support either 2D transformations or 3D transformations.

All modern browsers will support 3D transforms and several of the older legacy browser such as Internet Explorer 9 and Opera 11.5 will support 2D transforms. Overall support for both desktop and mobile browsers is comprehensive.

jQuery’s animate method works in any (sane) browser, provided you are using the 1.X version of the library. jQuery 2.X removed support for IE8 and below, so only use this if you don’t need to support legacy browsers (lucky you!).

Speed

We want fast and smooth animations, especially when it comes to mobile devices. As such its always best to use transitions and transformations where possible.

The examples will use 3D transforms with 2D fall-backs for older browsers. We want to force hardware acceleration for speed, so a 3D transformation is a must (we will be using translate3d along with other functions that cause GPU accelerated rendering).

jQuery’s animate method is considerably slower than a GPU assisted transformation, so we will just be using jQuery for our event handling / calculations, not for our animation itself (as we want them to be as smooth as possible).

Side Note

We all know that jQuery !== JavaScript, right? Well, it turns out that using vanilla JS for animations might not be such a bad an idea after all. Whilst that is beyond the scope of this tutorial, here are two excellent articles on the subject for those who are interested in finding out more:

Now back to the show …

Detecting Animation Elements in View

The overall point of this technique is to look through all of our elements we marked as animatable and then determine if they are currently within the viewport. Let’s step through how we will achieve this:

Selector Caching

Scrolling is an expensive business. If you attach an event listener to the scroll event, it will fire many times over whenever a user scrolls the page. As we will be calling our dimension / calculation functions whenever a user scrolls, it is a good idea to store the elements returned by our selectors in variables. This is known as selector caching and avoids us querying the DOM over and over again.

In our script we will be referencing both the window object and the collection of elements we want to animate.

//Cache reference to window and animation items
var $animation_elements = $('.animation-element');
var $window = $(window);

Notice the dollar sign in front of the variables. This is a convention to indicate that they hold a jQuery object, or collection of objects.

Hooking into the Scroll Event

Next, we create our event handler that listens for the scroll event. This will fire when we scroll the page. We pass it a reference to our check_if_in_view function (which we’ll get to in a minute). Every time the scroll event is fired, this function will be executed.

$window.on('scroll', check_if_in_view);

Handling Resizing

Because we are calculating heights and widths we need to factor in orientation changes along with general resizing.

We can update our event handler to listen for both the scroll and resize events. This will enable our detection function to work when we resize or change orientation.

$window.on('scroll resize', check_if_in_view);

In addition, we also use the jQuery trigger method to trigger a scroll event as soon as the DOM is ready. We do this so that if any of the elements which should be animated are within the viewport, they will be detected as in view and the animation applied as if we had scrolled.

$window.trigger('scroll');

Scroll Position Detection

The actual detection portion of this example comes from the following script.

function check_if_in_view() {
  var window_height = $window.height();
  var window_top_position = $window.scrollTop();
  var window_bottom_position = (window_top_position + window_height);

  $.each($animation_elements, function() {
    var $element = $(this);
    var element_height = $element.outerHeight();
    var element_top_position = $element.offset().top;
    var element_bottom_position = (element_top_position + element_height);

    //check to see if this current container is within viewport
    if ((element_bottom_position >= window_top_position) &&
        (element_top_position <= window_bottom_position)) {
      $element.addClass('in-view');
    } else {
      $element.removeClass('in-view');
    }
  });
}

Lets break down what is happening here.

The check_if_in_view function is called initially when the DOM is ready and then every time we resize or scroll.

We get the current height of the window, along with its top and bottom position so we know what area we are looking at.

We go through and look for all items that will be animating in (saved in the $animation_elements variable). For each of these elements we collect its height along with its top and bottom position (so we know where it lives on the page).

We compare each item to see if its bottom position is greater than the top position of the window but also that the item’s top position is less than the bottom position of the window.

Here is a visual example

Detect if element is within viewport

Calculating the Height and Width

In our detection function we need to get the heights and positions of various elements to calculate things correctly, this is where we have used jQuery’s height functions. It’s important to have a breakdown of how these height functions work

height() and width()

The height() and width() functions return the height or width of an element. They exclude all padding, borders and margins.

jQuery height and width example

For a full breakdown visit the height or width documentation.

innerHeight() and innerWidth()

The innerHeight() and innerWidth() functions return the height or width of the element including its additional padding (however it excludes both borders and margins)

jQuery innerHeight and innerWidth example

For a full breakdown visit the innerHeight or innerWidth documentation.

outerHeight() and outerWidth()

The outerHeight() and outerWidth() functions return the height or width of the element and include its padding and border.

In addition you can also specify to include its margins by passing a value of true to the function.

jQuery outerHeight and outerWidth example

For a full breakdown visit the outerHeight or outerWidth documentation

Scroll Animation Examples

Listed below are a series of animations that use the basics of what we have discussed. These examples will look for animation elements and apply the active in-view class when they’re within the viewport.

Elements that you want to move should all have a standard class such as animation-element that sets its position to be relative or absolute. In addition, if you are going to create multiple effects you can create corresponding classes such as slide-left which can be combined with the in-view class. You should then apply the transformation to a class such as animation-element.slide-left.inview

Slide in from Left

For our first example we will be sliding in elements from the left when they enter the viewport. We achieve this by using a translate3d on our elements x axis.

See the Pen CSS Animations on Scroll – Slide in From Left by SitePoint (@SitePoint) on CodePen.

In this example we have used it to display staff profiles, but you can re-leverage the same functionality to slide in any elements you need.

Fade in from Bottom

This time we will be fading our elements from the bottom upwards as the user scrolls. We achieve this via a translate3d on the element’s y axis.

For this example I’ve listed course information about topics in a grid structure. When the user scrolls down, each card in view will fade in and move up, displaying information about the course.

See the Pen CSS Animations on Scroll – Fade From Bottom up by SitePoint (@SitePoint) on CodePen.

Multi-Step Bouncing Animation

For our final example we’ll use a multistage animation. To do this, we’ll define custom keyframe animations that combine a rotation with a translation. This type of animation can help showcase areas of your website (for this example we are showcasing staff member profiles).

See the Pen CSS Animations on Scroll – Multi Step Move by SitePoint (@SitePoint) on CodePen.

Where to from Here?

From here you can take the concepts you have learned and apply them to your projects.

Now that you can detect when an element is in view you can chain additional transformations or effects to create interactive interfaces. For example when an element enters the viewport (and after its transformation) you can then transform additional elements such as fading in a title, scaling in an image etc.

Are you already using these effects in your projects? Or do you think that animations are overused and detract from the user experience? Either way I’d love to hear from you in the comments.

Tags: 'Animation and Effects', CSS3, jQuery, viewport
I'm a designer, developer and overall web enthusiast. I love everything to do with web and design and my passion resolves around creating amazing websites for my clients. Focusing primarily on WordPress, I create themes, plugins and solutions with my team over at Web Bird Digital.

Free Guide:

How to Choose the Right Charting Library for Your Application

How do you make sure that the charting library you choose has everything you need? Sign up to receive this detailed guide from FusionCharts, which explores all the factors you need to consider before making the decision.


  • Mr.Key

    Nice article. I was using animate.css and WOW.js without learning how it actually works. http://mynameismatthieu.com/WOW/

    • simon codrington

      Thanks @mrkey:disqus for the comment and the link :)

      I’ve used similar libraries before, but now that I understand how it all works its easier to make more intricate movements and functionality now.

  • eddie404

    Interesting article – thanks Simon. I have been avoiding animation because of browser compatibility and, truth be known, an element of ignorance on my part. I have already bookmarked the page and started testing. Thanks.

  • http://www.walabbady.com Waleed Alabbady

    WOW.js :)

  • Deepanshi Gupta

    how can I get complete code of last two animated images since I don’t know about js

    • simon codrington

      Hey @deepanshigupta:disqus what are you trying to do. Which last two images are you referring to?

  • Jose Manuel Mujica Puentes

    Thank you Simon, this is a great guide.

    • simon codrington

      Hey @josemanuelmujicapuentes:disqus thanks for the feedback :)

      Hopefully it will help you to build some fancy animations!

  • Daniel

    Hi – I am struggling with this a little bit as I have no understanding of Jquery and javascript. I have been trying to add this to my website for days but can never manage to get the on scroll to work. any chance of an idiot’s guide? Where do I place these scripts? In the head section ? And do I have to install anything on my website for it to work?

    • simon codrington

      Hey there Daniel, sorry for the late reply (notifications were off).

      Let me know if you’re still struggling with this and i’ll see what I can come up with :)

  • Sunny Israni

    HI Simon–this guide is beyond amazing! I just have a question though, what about tying the speed of the transitions to the speed at which the user is scrolling–I’m finding many websites these days that do just this, and havent the slightest idea how they go about doing it. I’m assuming this type of animation would be heavy on the JS/JQuery side, correct?

    • simon codrington

      Thanks for the feedback @sunnyisrani:disqus Glad to see that you found my article useful :)

      If you wanted to adjust the speed at which elements animate in the approach would be different depending on how you are animating.

      If you are using ‘transitions’ (as in just left: -100% to left 100%) you would have to change the ‘transition-duration’ to either a higher or slower number depending on scroll speed (i..e on a slow scroll we can transition in 1000ms, on a fast scroll we transition quickly in 300ms)

      In my example the `check_if_in_view()` function is called when we ‘scroll’. Inside here to detect the speed we would have to check the previous position we were at and then compare it to our current position we scrolled to. If we jumped a big distance we can assume we are scrolling really fast (this would be a process of trail and error and might be tricky to set up)

      If you are using ‘keyframe animations’ it would be harder as you would have to calculate the speed you want and then re-write the css animation. For example one of the animations is: animation: left_animation 1300ms ease-in both; To change this you would have to detect the speed and then re-write the rule dynamically i.e animation: left_animation 955ms ease-in both; (on a faster scroll)

      You would also need to add the vendor prefix versions like ‘-webkit-transform’ also.

      Changing the timing on that would mean potentially you re-declare the new animation dozens of times as you scroll (which may impact performance, I’m not 100% sure how badly though)

      It’s all possible but I think it would be a heap of testing to get it correct :)

      Hopefully some of this helps

  • zulius akbar

    thanks :) very help me,

    • simon codrington

      No worries, glad the article was useful for you :)

  • Rhomy Prama Design (Web Design

    Thanks, its realllyy help me. God Bless You, keep sharing. :)

  • Susheel Sundar

    Simon which js libraries we should add to make this work?

Special Offer
Free course!

Git into it! Bonus course Introduction to Git is yours when you take up a free 14 day SitePoint Premium trial.