Building Interactive Scrolling Websites with ScrollMagic.js

ScrollMagic is a jQuery plugin which lets you use the scrollbar like a playback scrub control. Using this, you can build some extremely beautiful landing pages and websites. Normally, we wouldn’t do a tutorial on using a single jQuery plugin, but scrollMagic does a lot and has quickly become one of my favorite plugins. In this article, I’ll cover my general opinion on scroll plugins, how to get started with ScrollMagic, and some basic and over-the-top creative demos. Finally, some starter templates for you to repurpose are in works to be released very soon in part II of this tutorial.

A Note About a User’s Scroll

I’m not a fan of hijacking a users scroll period. I personally believe it’s way to easy to ruin a user’s experience and it makes it difficult to quickly navigate to specific content. It takes a lot for me to consider using a jQuery plugin that heavily affects normal scroll behavior. ScrollMagic doesn’t really hijack a users scroll despite its name alluding to the idea that it would. It simply just triggers a bunch of events during a user’s scroll. For example, compare these two sites:

Notice that with the Google Cardboard site you can quickly navigate up and down, but with fullPage.js you’re actually restricted and delayed on your scrolling. FullPage.js is nevertheless a great and impressive plugin, it’s just not user experience I like to create.

Lastly, if you check out ScrollMagic’s demo page you’ll see a ton of crazy animations. The demo is definitely over the top and doesn’t really do justice for the advantages of using ScrollMagic in simpler designs. I hope after reading this article though that you understand and enjoy the benefits as much as I do.

Here’s a little sample of one of the things we’ll be able to build:

See the Pen ScrollMagic Demos – Class Toggles by Nicholas Cerminara (@ncerminara) on CodePen.

Initial Setup

To get started you’ll need a few dependencies.

jQuery

Official Resource

ScrollMagic requires jQuery. You’ll need to include to be able to even use ScrollMagic. I’m going to include the latest jQuery before it dropped Internet Explorer 8 support (jQuery 2.x+) despite ScrollMagic only supporting Internet Explorer 9 and above.


<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

GreenSock Animation Platform (GSAP)

Official Resource

ScrollMagic uses the GreenSock Animation Platform (GSAP) for doing animations. Technically, the GreenSock platform is completely optional, but it makes total sense to use it. GSOP is nice because it has it’s own little framework with its own dependencies and plugins. If performance is a huge factor for you, you can pick and choose only exactly what you need. However, we’re going to use the whole library to take advantage of all it’s cool features.


<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.14.2/TweenMax.min.js"></script>

ScrollMagic

Official Resource

Next, you’ll need to include ScrollMagic. ScrollMagic also comes with a nice but separate debugging library. I’ll include it for the demos, but on production environments, there’s no need to include it.


<script src="jquery.scrollmagic.min.js"></script>
<script src="jquery.scrollmagic.debug.js"></script>

All At Once

And here it is all together with the full HTML and references to Bootstrap for CSS:


<!doctype html>
<!--[if lt IE 7 ]><html id="ie6" class="ie ie-old ie-super-old"><![endif]-->
<!--[if IE 7 ]>   <html id="ie7" class="ie ie-old ie-super-old"><![endif]-->
<!--[if IE 8 ]>   <html id="ie8" class="ie ie-old ie-super-old"><![endif]-->
<!--[if IE 9 ]>   <html id="ie9" class="ie ie-old"><![endif]-->
<!--[if gt IE 9]><!--><html><!--<![endif]-->
<head>

    <!-- Meta -->
    <meta charset="utf-8">
    <title>Scotch Magic ♥</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta content="yes" name="apple-mobile-web-app-capable">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

    <!-- Favicons -->
    <link rel="shortcut icon" sizes="16x16 24x24 32x32 48x48 64x64" href="/wp-content/favicon.ico">

    <!-- Styles -->
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css">
    <!--[if lt IE 9]>
        <script src="//oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
        <script src="//oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" href="style.css"><!-- Reference to your stylesheet -->

</head>
<body>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.14.2/TweenMax.min.js"></script>
    <script src="jquery.scrollmagic.min.js"></script>
    <script src="jquery.scrollmagic.debug.js"></script><!-- Dev only -->
    <script src="power.js"></script><!-- scripts.js, main.js, etc. -->

</body>
</html>

The ScrollMagic Controller

Typically when you initiate a jQuery plugin you just pass a bunch of options and call it a day. Sometimes a plugin will have advanced features like a callbacks API or the ability to return the entire plugin as an object with some public functions so you can get real custom with it.

ScrollMagic is a little bit different than this. We’re going to initiate a ScrollMagic Controller, create a bunch of animation objects, create some Scene (where the animation happens) objects, combine the animation and scene objects, then pass it all back to the main ScrollMagic Controller. So our general steps will be:

  1. Create the ScrollMagic Controller (and select general options)
  2. Create an Animation Object (and select animation options)
  3. Create a Scene Object (and select scene options)
  4. Add our Animation Object to the Scene Object
  5. Add the Scene Object to the ScrollMagic Controller

It’s nothing too crazy as it’s your typical JavaScript stuff, but understanding the underlying structure of how it all plays together will help you move forward with it. It’s a little bit more involved than your standard jQuery plug and chug plugins.

Now, all that being said, this is how to initiate the ScrollMagic Controller:

$(function() {
    // Init Controller
    var scrollMagicController = new ScrollMagic();
});

Basic Example

Now let’s create the two most basic examples that ScrollMagic does for us.

Animation Trigger Example

All this does is trigger an animation. We’ll do two things to get this working. First, create the Animation on the element we want to animate. Then, second, we’ll create the Scene which is going to trigger the animation when it is scrolled into view. So, let’s go ahead and create that first animation (we’ll cover these more in depth further in the article):

// Create Animation for 0.5s
var tween = TweenMax.to('#animation', 0.5, {
    backgroundColor: 'rgb(255, 39, 46)',
    scale: 7,
    rotation: 360
});

Pretty simple! This will add those CSS properties to the element with the ID of #animation. However, we need to control when those animations happen. ScrollMagic will make it easy to bind the animation to certain scroll events by creating Scenes. Here’s the next piece of code:

// Create the Scene and trigger when visible with ScrollMagic
var scene = new ScrollScene({
    triggerElement: '#scene',
    offset: 150 /* offset the trigger 150px below #scene's top */
})
.setTween(tween)
.addTo(scrollMagicController);

We create the Scene as an object to be triggered later, then we pass which animations we want to that Scene, and, finally, we pass it all back to the ScrollMagicController to be handled. Here’s a stripped and naked example to help explain:

See the Pen ScrollMagic Demos – Basic Example by Nicholas Cerminara (@ncerminara) on CodePen.

Animations Binded to Scroll

The last example only triggers the animation at the specified Scene trigger point. ScrollMagic can bind your animation to the scroll event. This acts as a rewind and fast-forward scrubber for your animation. Here’s the code for doing that:

// Duration ignored / replaced by scene duration now
var tween = TweenMax.to('#animation', 0.5, {
    backgroundColor: 'rgb(255, 39, 46)',
    scale: 5,
    rotation: 360
});

var scene = new ScrollScene({
    triggerElement: '#scene',
    duration: 300 /* How many pixels to scroll / animate */
})
.setTween(tween)
.addTo(scrollMagicController);

You should immediately see that the only difference that matters between the two examples is that the duration property is added to the scene. This will be how many pixels you want the animation to be on scroll. Here’s an example to visualize that difference between the two methods:

See the Pen ScrollMagic Demos – Animations Binded to Scroll by Nicholas Cerminara (@ncerminara) on CodePen.

Tween Animations in Depth

There’s a ton of options for doing animations. I’ll cover some of the more various ones, but, first let’s do the most common one – “tweening” using the GreenSock Animation Platform.

Tweening is what the GSAP calls their animations. We’re specifically using their TweenMax library. TweenMax is awesome because it encompasses all their various plugins and additions into one. This gives us some cross-browser stuff, makes the browser use CSS3 animations first, is extremely performant, and it let’s you create complex animations and key frames with ease. Alternatively, you can work piecemeal and pick exactly which components you want with TweenLite and its plugins.

TweenMax.to()

This lets us create our most standard animations. For example if you want an element’s background color to go from it’s default to red. Here’s an example:


// TweenMax.to(selectorOfElementYouWantToAnimate, DurationOfAnimation, AnimationProperties);
var tween = TweenMax.to('#first-animation', 0.5, {backgroundColor: 'red'});

You can get as infinitely creative as you want with this. For example, the following tween will make the background red, it grow 5 times in size, and do a full spin rotation using CSS3 Transforms.


var tween = TweenMax.to('#first-animation', 0.5, {
    backgroundColor: 'red',
    scale: 5,
    rotation: 360
});

You can do pretty much anything you would be able to do with CSS3 animations – colors, transforms, etc. Here’s the official resource so you can reference for syntax. You can view the examples directly above to see the TweenMax.to() function in action.

TweenMax.from()

This works exactly the opposite of TweenMax.to(). It will animate to the default styles from the specified animation options. Here’s some example code:

var tween = TweenMax.from('#animation', 0.5, {
    backgroundColor: 'rgb(255, 39, 46)',
    scale: 5,
    rotation: 360
});

Here’s an example from one of the basic demos using the from() function instead:

See the Pen ScrollMagic Demos – Animation Trigger by Nicholas Cerminara (@ncerminara) on CodePen.

TweenMax.fromTo()

This function is exactly what it sounds like. You’ll specify two animation properties for it to animate from one and then to the other. Hopefully you’re wondering why you can’t just use the to() function and set the start styles with CSS. Well, you can and that’s totally okay. The function fromTo however introduces a bunch of other options like yoyo and repeat. So you use those to create keyframe animations when the scroll event is triggered. Check out the code below:

var tween = TweenMax.fromTo('#animation', 0.5,
    {
        backgroundColor: 'rgb(255, 39, 46)',
        scale: 5,
        left: -400
    },
    {
        scale: 1,
        left: 400,
        rotation: 360,
        repeat: -1, /* Aka an infinite amount of repeats */
        yoyo: true /* Make it go back and forth or not */
    }
);

See the Pen TweenMax.fromTo() with Repeat and Yoyo Turned On by Nicholas Cerminara (@ncerminara) on CodePen.

See the Pen TweenMax.fromTo() with Repeat and Yoyo Turned Off by Nicholas Cerminara (@ncerminara) on CodePen.

With both of these examples, if you remove the Scene’s duration, there will be no endpoint for the animation to stop.

Staggering

You can easily have multiple elements have the same animation and different start times all within the same Scene. This is called staggering and is very easy to do. Here’s a code sample followed by a demo:

var tween = TweenMax.staggerFromTo('.animation', 0.5,
    {
        scale: 1,
    },
    {
        backgroundColor: 'rgb(255, 39, 46)',
        scale: 5,
        rotation: 360
    },
    0.4 /* Stagger duration */
);

See the Pen ScrollMagic Demos – Staggering Animations by Nicholas Cerminara (@ncerminara) on CodePen.

Additional Animations

There’s even more things you can do. For example, you can animate to all the CSS properties of contained in a certain class. You can also chain animations together to get even more complex and creative. This article won’t cover all that, but you can check out the docs here for more information.

CSS Class Toggles

ScrollMagic also lets you easily toggle as many classes as you want when the Scene is activated. This is super handy for doing some complex stuff without the additional JavaScript. For example, if we wanted to just toggle a body class to change some colors around, all we would need to do is add the following code to the Scene.

.setClassToggle('body', 'scene-is-active')

This brings so much control and power in my opinion. Check out the quick demo I put together to demonstrate the extra amount of depth you gain.

See the Pen ScrollMagic Demos – Class Toggles by Nicholas Cerminara (@ncerminara) on CodePen.

Custom Containers and Mobile Support

I bunched custom containers and mobile support together because they’re really one and the same. Typically on a mobile touch device, the scroll event isn’t detected until the scroll has stopped. This is unfortunate for what we’re doing. Fortunately that only occurs when you’re scrolling on the entire body. If say your scrolling in an element that is set to overflow: scroll each moment of the scroll is detected.

ScrollMagic lets you specify any container you want for your scenes by a simple option. Here’s a code example:


var scrollMagicController = new ScrollMagic({container: '#my-container'});

You can do cool things with this like putting your animations and scroll inside of a div or section of your website. Mobile support takes this exact same concept and creates a “container” or wrapper around the whole site and just binds ScrollMagic to that container.

Truth be told it’s a hackish workaround. The major downside is this kills off support for momentum scrolling. ScrollMagic’s official answer to this is to use something like iScroll.js to bring scroll momentum to touch devices. You may also be able to just add this CSS3 property to the container -webkit-overflow-scrolling: touch;, but that obviously won’t work in all browsers. It’s entirely up to you to support this or not, but if you get it right it can really provide a seamless experience on mobile.

Lastly, if you want to just disable ScrollMagic on mobile or touch devices, you can do it easily with Modernizr:

if (!Modernizr.touch) {
    // Start ScrollMagic code
}

If you’re not a fan of using another library like Modernizr just to detect touch, you can use this function:

if (!is_touch_device()) {
    // Start ScrollMagic code
}
function is_touch_device() {
  return 'ontouchstart' in window // works on most browsers 
      || 'onmsgesturechange' in window; // works on ie10
};

I grabbed that function from this StackOverflow post. It seems to update a lot in case you want to check to see if that’s still up to date.

Conclusion

ScrollMagic’s official documentation and examples are amazing. I definitely recommend heading over there and checking out all the other things ScrollMagic can do. Some of those things include:

There’s definitely a lot you can do with ScrollMagic. I think it’s generally smart to use this with caution in risk of ruining a user experience with some bad animations. Complex ScrollMagic websites are probably best saved for landing pages and using this subtly is best with content based websites. It’s all about finding a balance. That being said, I plan on releasing some starter templates soon that would be good for portfolios, product launches, and stuff like that. Stay tuned!