The modern website expects to have more than simple style, as web developers we want that users enjoy what they are seeing, staying longer on our site and have more interaction with content. To achieve the desired goals, we need to add animations to our UI elements.
In this article, I'll talk about animations implemented with GreenSock, although you can always animate your elements with other animation tools like CSS-animations, TweenJS, etc.
Green Sock Animation Platform is a popular JavaScript animation platform with lots of functionality, implementations, and plugins. It changes properties many time per second, making elements appear, move, spin, fade, etc. GSAP catches a starting value, ending value and then interpolates between them 60 times per second. We'll see an example below. Generally, you can animate/morph/draw SVGs, dragging elements on the screen, making motions, and so on.
The starting point of every animation in GSAP is Tween. Tween is a single movement in animation. It has the following syntax:
Tween.method(element, duration, props)
UPDATE: since November, it was released version 3 of GSAP with some simplified version of using "Tween". Read more here.
Method refers to the GSAP method you’ll like to tween with.
Element is the element you want to animate. If you want to create tweens for multiple elements at the same time, you can pass an array of elements.
Duration is the duration of your tween. It is an integer in seconds.
Props is an object of the properties passed to your animation. More on this later.
Let's say you have a horizontal line (like in our page on section "careers") you want to go from position x = 0 to the full width of the viewport with nice easing.
Firstly we'll take our Tween to use method to(), pass element that we want to animate (".line") and set the duration of our animation, e.g., "duration": 8.
TweenLite.to(".line", 8)"
Now, as mention above, we need to put properties that we want animate. In CSS I define starting position as width: 0
.
const props = {"width": "100%", "ease": "Power2.easeOut"}
I'm using Power2.easeOut, but you can choose ease witch suits you more.
Finally, we put our props as an argument in to() method
TweenLite.to(".line", 0.8, props)
See the full example here.
As you probably noticed above, our animation is triggered immediately on content load. In most cases, we want to wait until the user scroll to specified content.
To achieve that, we use ScrollMagic, a simple JS library that detects the user's current scroll position.
The idea behind ScrollMagic is to have one Controller, which has one or more Scenes attached to it. Basically, Scene is what happened when the user scrolls to specificated element.
When working with animations, we presume that every element must be possible to animate. To achieve this, we somehow need to specified elements which, and how, will be animated. For that purpose, we're be using HTML custom attributes. Shortly, HTML custom attributes store some data of elements.
First, we'll retrieve all the elements that have our custom HTML attribute
const elements = document.querySelectorAll("[data-animate]");
Secondly, we'll make a script to handle our selected elements
function transformAnimation (elements) {
elements.forEach(function (el) {
const from = JSON.parse(el.dataset.from);
const to = JSON.parse(el.dataset.to);
TweenLite.fromTo(el, to.duration, from, to);
});
}
You may notice that we're also using "dataset" to parse data from custom HTML attribute. The purpose of this is to set all required data inside element's tag. Finally:
<div class="className" data-transform data-from='{"opacity": 0, "y": "15%"}' data-to='{"opacity": 1, "duration": 0.8, "ease":"Power2.easeOut", "y":"0%"}'>
The same logic will be implemented on elements which animations need to be triggered on the specified position of scroll.
function triggerOnScroll(trigger, elements) {
const scene = new ScrollMagic.Scene({triggerElement: trigger})
.addTo(controller)
.reverse(false)
.on("start", function () {
transformAnimation([elements])
})
}
Our assumption above needs to be expended with "...differently on every device". That means, if you need to animate elements differently on mobile, you'll use the same logic as mentioned. Define custom mobile data attribute, set properties you'd like to animate, and use it on mobile animation script.
At the end, there's always a questions Why should I use GSAP when I have CSS animations? and Isn't writing CSS animations cleaner then JS animations? If you check the codepen animation test, you'll see that GSAP performs on more frames per second(FPS). Beside, animations works on every browser. There's no need for using vendor prefixes. Also, GSAP is modular, that means if you need to make the smallest change, there's no need to rewriting all of your "animation logic". Unlike with CSS-animations where you need to change all the keyframes with from and to or percentages offset with @keyframe rule.
Writing animation properties inside HTML tags can lead to a "bloating" code. That means if lots of elements need to be animated, there will also be lots of code inside tags. In other words, code will become non-transparent. Besides, if you need to change some value, there's always a possibility to spend some time to find it.
On the other hand, there's no need for repeating JS code for animations. You have a few scripts that handle all animated elements and all kinds of animations, e.g., staggering, fading, etc.