Create a Distortion Effect Using GSAP
Animating DOM elements on the web has been one of the many topics with numerous solutions. We have seen the rise of HTML and CSS classic design systems, and how to structure keyframe animations accordingly. Then, we transitioned into using javascript libraries like jQuery, only to now be trumped by more efficient and performant libraries, one of which is GSAP.
####Introduction GSAP (GreenSock Animation Platform), as indicated by the Getting Started guide, “is a suite of tools for scripted animations”. What that basically means, is that it is one big ecosystem of ready-made functions and methods you can use to animate literally anything on the DOM. What makes GSAP so great, is that it is fully optimized for performance and scaling, even when building complex animation. This is what makes it trump over jQuery, as well as its minimal code style in contrast to jQuery’s robust syntax.
####What will we be building?
In this article, you will learn how to build a cool-looking webpage with a distortion effect that gets triggered on hover, using GSAP
and hover-effect
library. This example will help us shorten the learning curve with GSAP.
Credits go to:
UI Designer: Maxim Nilov | Dribbble
Github: codicts/Fashion-Landing-Page (github.com)
####Prerequisites
GSAP
is a suite that makes rendering on the DOM a lot easier, and this is made possible by using a few key concepts that are related to DOM manipulation, much like every other framework for the web. To this end, you will need to know:
- HTML, CSS and Javascript
- Basic React
####How does GSAP work?
GSAP
has built-in components to help create these animations, and they come with methods that help us set the properties we want to animate. For this example, we will only need one of these components, which is the TweenMax
. (Please check out their docs:).
####TweenMax
The Tween and TweenMax components are one of the more widely used ones, in that they make it easy to do the simple transitions without writing complex keyframes. The tween
keyword is derived from ‘between’, which basically means “change this property between a given duration from one value to another”.
Let’s take a look at some of the methods that exists within GSAP:
- gsap.to()
- gsap.from()
- gsap.staggerFrom()
####gsap.to()
Here, we tell gsap
to change the property of a given value to another as well, but in this case, we indicate the starting value of the animation.
Here’s an example:
gsap.from("#logo", {duration: 1, x: 100});
####Gsap.staggerFrom()
Now staggerFrom
works a bit differently from gsap.to()
and gsap.from()
. With to and from, we deal with a single HTML element that we want to animate, but what if we want to animate a group of elements, particularly children of a parent element? With staggerFrom()
, we can set an animation to take effect for a group of child elements, and even set an interval or “stagger” between the elements, to give it this sequential feel as they get animated.
Here’s an example of using this:
TweenMax.staggerFrom(".media ul li", 1.5, { //TweenMax used in place of gsap
delay: 1.5,
opacity: 0,
x: "-60",
ease: Expo.easeInOut
}, 0.08);
First, we call the gsap
library (TweenMax), then we can use the “staggerFrom()” method to target the HTML <li/>
elements under the media
class. The value 1.5
is used to indicate the stagger to be affected between the start time of each child’s animation. This stagger is what helps the animations to have a sequential feel between them.
Then we put in the properties we want for each element. Note the ease
property, which you can learn more about in their documentation.
####Getting Started with GSAP Now let’s get started with building our distortion effect page. Create your folder and in that new folder, create your HTML and CSS files. Then in your HTML file, you set up your basic HTML markup.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
Next, our imports:
<!-- google fonts -->
<link href="https://fonts.googleapis.com/css?family=Poppins:500,600,700,900&display=swap" rel="stylesheet">
<!-- css -->
<link rel="stylesheet" href="style.css">
Then our scripts as well, for GSAP and hover-effect (these go on the bottom of the html page)
<!-- icons -->
<script src="https://unpkg.com/ionicons@4.5.10-0/dist/ionicons.js"></script>
<!-- gsap -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"
integrity="sha256-lPE3wjN2a7ABWHbGz7+MKBJaykyzqCbU96BJWjio86U=" crossorigin="anonymous"></script>
<!-- three js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.min.js"
integrity="sha256-3mBEX8I0uMLF7+AUjJeTCelosuorzYpqwBMBPDTyQqY=" crossorigin="anonymous"></script>
Now we are set to get started with our web page. You can set up the views to your convenience, but for this tutorial, we will first set up the main webpage.
<!-- NAVBAR
=============================== -->
<nav class="navbar">
<div class="menu">
<ion-icon name="ios-menu"></ion-icon>
</div>
<div class="lang">eng</div>
<div class="search">
<ion-icon name="ios-search"></ion-icon>
</div>
</nav>
<!-- SOCIAL MEDIA
=============================== -->
<div class="media">
<ul>
<li>facebook</li>
<li>instagram</li>
<li>twitter</li>
</ul>
</div>
<!-- TEXT
=============================== -->
<div class="text">
<h1>
<span class="hidetext">toni&guy</span>
</h1>
<h2>duality</h2>
<h3>
<span class="hidetext">collection 2017 <br> duality</span>
</h3>
<p>
<span class="hidetext">
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Unde quis, delectus facere
neque sunt commodi quae
culpa dolores doloribus magnam?
</span>
</p>
</div>
<!-- SPONSOR
=============================== -->
<div class="sponsor">
<img src="./images/sponsor-logo.png" alt="">
<p>official sponsor</p>
</div>
Then the CSS for the basic webpage:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Poppins';
background: #D8DBE2;
width: 100%;
height: 100vh;
overflow: hidden;
}
ul {
list-style: none;
}
/* NAVBAR
=========================== */
.navbar {
display: flex;
justify-content: space-between;
height: 80px;
align-items: center;
}
.navbar > div {
padding: 0 30px;
font-size: 20px;
}
.navbar .menu {
margin-right: auto;
}
.navbar .lang {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
}
/* SOCIAL MEDIA
=========================== */
.media ul {
position: absolute;
bottom: 250px;
left: -140px;
transform: rotate(-90deg);
}
.media ul li {
font-size: 10px;
font-weight: 600;
letter-spacing: 2px;
display: inline-block;
padding: 0 30px;
}
/* TEXT
=========================== */
.text {
position: absolute;
top: 200px;
left: 100px;
transform: rotate(-90deg);
}
.text h1 {
font-size: 120px;
text-transform: uppercase;
font-weight: 900;
letter-spacing: -10px;
margin-bottom: 20px;
position: relative;
overflow: hidden;
height: 150px;
width: 600px;
}
.text h1 .hidetext {
position: absolute;
}
.text h2 {
position: absolute;
top: 40px;
left: -80px;
color: #EFDE74;
z-index: -1;
font-size: 150px;
font-weight: 600;
letter-spacing: 8px;
text-transform: uppercase;
}
.text h3 {
font-size: 40px;
text-transform: uppercase;
font-weight: 600;
line-height: 1;
position: relative;
overflow: hidden;
height: 80px;
}
.text h3 .hidetext {
position: absolute;
}
.text p {
width: 200px;
font-size: 12px;
margin-top: 30px;
font-weight: 500;
position: relative;
overflow: hidden;
height: 110px;
}
.text p .hidetext {
position: absolute;
}
/* SPONSOR
=========================== */
.sponsor {
position: absolute;
right: 100px;
bottom: 100px;
text-align: center;
}
.sponsor img {
width: 200px;
transform: rotate(-90deg);
}
.sponsor p {
margin-top: 20px;
font-size: 12px;
text-transform: uppercase;
font-weight: 900;
transform: rotate(180deg);
}
Let’s examine our webpage:
Here are a few things we can see: 3 squares animate from bottom to top, to reveal the webpage. Here, we already know they will be 3 divs to have a position absolute, and then we use the “to” method to animate between them. Navbar above, animate from top to bottom, with changed opacity. Text on the side changes from 0 to 1 and increases in height.
For the 3 squares, we create 3 divs to represent them.
<div class="overlay first"></div>
<div class="overlay second"></div>
<div class="overlay third"></div>
Then we style accordingly in the styles.css
/*=========================== OVERLAY =========================== */
.overlay {
position: absolute;
width: 100%;
height: 100%;
top: 0%;
z-index: 99;
}
.first {
background: #efde74;
}
.second {
background: #efde74;
left: 33.3%;
}
.third {
background: #efde74;
left: 66.6%;
}
Now we can set up our animation with GSAP
:
TweenMax.to(".first", 1.5, {
delay: .5,
top: "-100%",
ease: Expo.easeInOut
});
TweenMax.to(".second", 1.5, {
delay: .7,
top: "-100%",
ease: Expo.easeInOut
});
TweenMax.to(".third", 1.5, {
delay: .9,
top: "-100%",
ease: Expo.easeInOut
});
Notice that the delay has been varied by .2 to have that effect. You could also use the staggerFrom()
method to vary between the children and see how the effect varies.
Next, we animate our navbar and various texts. Here’s a few things we can see: 3 squares animate from bottom to top, to reveal the webpage. Here, we already know they will be 3 divs to have a position absolute, and then we use the “to” method to animate between them. Navbar above, animate from top to bottom, with changed opacity. Text on the side changes from 0 to 1 and increases in height.
For the 3 squares, we create 3 divs to represent them.
Then we style accordingly in the styles.css /=========================== OVERLAY =========================== / .overlay { position: absolute; width: 100%; height: 100%; top: 0%; z-index: 99; } .first { background: #efde74; } .second { background: #efde74; left: 33.3%; } .third { background: #efde74; left: 66.6%; }
Now we can set up our animation with GSAP: TweenMax.to(".first", 1.5, { delay: .5, top: "-100%", ease: Expo.easeInOut });
TweenMax.to(".second", 1.5, {
delay: .7,
top: "-100%",
ease: Expo.easeInOut
});
TweenMax.to(".third", 1.5, {
delay: .9,
top: "-100%",
ease: Expo.easeInOut
});
Notice that the delay has been varied by .2 to have that effect. You could also use the staggerFrom() method to vary between the children and see how the effect varies.
Next, we animate our navbar and various texts. // NAVBAR TweenMax.staggerFrom(".navbar div", 1.5, {
delay: 1.5,
opacity: 0,
y: "20",
ease: Expo.easeInOut
}, 0.08);
// MEDIA
TweenMax.staggerFrom(".media ul li", 1.5, {
delay: 1.5,
opacity: 0,
x: "-60",
ease: Expo.easeInOut
}, 0.08);
// TEXT
TweenMax.from(".text h1 .hidetext", 1.5, {
delay: 1,
y: "100%",
ease: Expo.easeInOut
});
TweenMax.from(".text h3 .hidetext", 1.5, {
delay: 1.2,
y: "100%",
ease: Expo.easeInOut
});
TweenMax.from(".text p .hidetext", 1.5, {
delay: 1.3,
y: "100%",
ease: Expo.easeInOut
});
TweenMax.from(".text h2", 1.5, {
delay: 1.5,
opacity: 0,
x: "-10000",
ease: Expo.easeInOut
});
// SPONSOR
TweenMax.from(".sponsor img", 1.5, {
delay: 1.5,
opacity: 0,
y: "20",
ease: Expo.easeInOut
});
TweenMax.from(".sponsor p", 1.5, {
delay: 1.6,
opacity: 0,
y: "20",
ease: Expo.easeInOut
});
Lastly, for the distortion effect, we will make use of the hover-effect library. You can get the hover-effect library here, then copy the code, create a new file called hover-effect.umd.js and paste the code. Then we import our newly created script:
Now, how our distortion effect works, is that the library will create a blur of the current image, then transition into a displacement image we will need to provide, then lastly transition to a blurred version of the second image to be transitioned into, and then set the image from a blurred state to a regular state. So first, we create a div which will represent our distortion image container.
So we need to provide a displacement image, (which should look like a blur effect for convenience), and then the two images to transition between:
new hoverEffect({
parent: document.querySelector('.distortion'),
intensity: 0.2,
image1: './images/01.png',
image2: './images/02.png',
displacementImage: './images/diss.png',
imagesRatio: 340 / 300
})
And that puts together the distortion effect with some animation. Thanks for reading.
// NAVBAR
TweenMax.staggerFrom(".navbar div", 1.5, {
delay: 1.5,
opacity: 0,
y: "20",
ease: Expo.easeInOut
}, 0.08);
// MEDIA
TweenMax.staggerFrom(".media ul li", 1.5, {
delay: 1.5,
opacity: 0,
x: "-60",
ease: Expo.easeInOut
}, 0.08);
// TEXT
TweenMax.from(".text h1 .hidetext", 1.5, {
delay: 1,
y: "100%",
ease: Expo.easeInOut
});
TweenMax.from(".text h3 .hidetext", 1.5, {
delay: 1.2,
y: "100%",
ease: Expo.easeInOut
});
TweenMax.from(".text p .hidetext", 1.5, {
delay: 1.3,
y: "100%",
ease: Expo.easeInOut
});
TweenMax.from(".text h2", 1.5, {
delay: 1.5,
opacity: 0,
x: "-10000",
ease: Expo.easeInOut
});
// SPONSOR
TweenMax.from(".sponsor img", 1.5, {
delay: 1.5,
opacity: 0,
y: "20",
ease: Expo.easeInOut
});
TweenMax.from(".sponsor p", 1.5, {
delay: 1.6,
opacity: 0,
y: "20",
ease: Expo.easeInOut
});
Lastly, for the distortion effect, we will make use of the hover-effect library. You can get the hover-effect library here, then copy the code, create a new file called hover-effect.umd.js and paste the code. Then we import our newly created script:
<!-- hover-effect js -->
<script src="./hover-effect.umd.js"></script>
Now, how our distortion effect works, is that the library will create a blur of the current image, then transition into a displacement image we will need to provide, then lastly transition to a blurred version of the second image to be transitioned into, and then set the image from a blurred state to a regular state. So first, we create a div that will represent our distortion image container.
<!-- DISTORTION =============================== -->
<div class="distortion"></div>
So we need to provide a displacement image, (which should look like a blur effect for convenience), and then the two images to transition between:
new hoverEffect({
parent: document.querySelector('.distortion'),
intensity: 0.2,
image1: './images/01.png',
image2: './images/02.png',
displacementImage: './images/diss.png',
imagesRatio: 340 / 300
})
And that puts together the distortion effect with some animation.
Thanks for reading.
Originally written by King Somto for JavaScript Works