Use CSS and jQuery to create on scroll animation

An increasingly popular effect observed on Reebok’s Be More Human site is achievable via the use of a jQuery plugin and simple CSS animation


An increasingly popular effect observed on Reebok’s Be More Human site is achievable via the use of a jQuery plugin and simple CSS animation


Identify the effect

Something you’ll notice on Reebok’s Be More Human site is a popular trick for pushing page content into view as you scroll. On a page such as the one for the Gray Matters section (, you’ll see the effect put to good effect. For emulating the UI behaviour of mobile apps, we’ll look at a method for achieving a similar effect with jQuery and CSS.

jQuery Visible plugin

In this instance the effect almost appends content on first scroll only, as if you are ‘building’ the page dynamically with fresh content. One of the first problems to overcome here is whether your statically defined HTML elements are visible within the browser’s viewport. A clever little jQuery plugin called jQuery Visible by Sam Sehnert is of real use here and available to download via GitHub at

001 <script src=""></script>    002 <script src="jquery.visible.js"></script>

Detect element visibility

With this plugin downloaded and attached to your jQuery-equipped page, call a single line of code to ascertain if a page element is visible to the user inside the current viewport. By passing various optional selectors and parameters, the plugin can detect whole or partial element visibility within the viewport as well as filtering element visibility as defined within CSS:

001 // Returns true if whole element is visible:             
002 $('#element').visible();
003 //Returns true if just part of the element is visible:
004 $('#element').visible(true);
005 //Filters CSS visibility state:     
006 $('#element:visible').visible();      
007 //Filters CSS visibility and checks viewport:        
008 $('#element:visible').visible(false, true);     

Elements already visible?

The solution we’ll examine derives from a Chris Coyier ( method for toggling CSS classes on a series of identical, relatively positioned elements populating a page. By calling the jQuery Visible plugin to check the initial viewport visibility of each element pertaining to a parent class (.content). We can attach a class to override any slideIn animation we’ll add to those made visible on scroll.

001 CSS:    
002 .inView {    
003 opacity: 1;
004 -webkit-transform: translateY(0);
005 -ms-transform: translateY(0);    
006 transform: translateY(0);    
007 -webkit-animation: none;    
008 animation: none;    
009 }  
011 $(".content").each(function(index,     element) {    
012 if ($(element).visible(true,     'vertical')) { 
013 $(element).addClass("inView");
014 }        
015 });

Check visibility on scroll

The second piece of JavaScript is triggered on window scroll. It grabs the current vertical scroll bar position, and compares to a previous value so we only perform the effect below the viewport and not above. If true, check the latest newly visible elements, attaching a slideIn class that contains our desired animations:

001 JAVASCRIPT:     
002 var prevScrollTop = 0;        
003 $(window).scroll(function(event) {     
004 var scrollTop = $(this).scrollTop();        
005 if (scrollTop > prevScrollTop){     
006 $(".content").each(function(index,     element) {    
007 if ($(element).visible(true,     'vertical')) {            
008 $(element).addClass("slideIn");    
009 }    
010 });     
011 prevScrollTop = scrollTop;         
012 }     
013 });

The CSS animation classes

We want the relatively positioned elements to slide up into view so a translateY() for vertical motion is desired by however many pixels. Duration and timing are again variable but a ‘forwards’ animation-fill-mode is critical to maintaining the new styles upon animation. By also setting opacity first to zero, then one (full) in our @keyframes class, we can have it gradually become opaque as it returns to a defined position on the y axis:

001 CSS:     
002 .slideIn {                 
003 opacity: 0;
004 -webkit-transform: translateY(200px);             
005 -ms-transform: translateY(200px);
006 transform: translateY(200px);
007 -webkit-animation-name: slideIn;
008 animation-name: slideIn;        
009 -webkit-animation-duration: 1.5s;    
010 animation-duration: 1.5s;
011 -webkit-animation-fill-mode:forwards;    
012 animation-fill-mode: forwards;    
013 }
014 /*.inView class here or below next class!*/    
015 @keyframes slideIn {        
016 to {    
017 opacity: 1;    
018 -webkit-transform: translateY(0);    
019 -ms-transform: translateY(0);    
020 transform: translateY(0);    
021 }    
022 }