GreenSock Tutorial: How To Create A Simple Image Slideshow

GreenSock Tutorial – How To Create A Simple Image Slideshow

We’ve covered the fundamentals of GreenSock and moved a few boxes using TweenLite and TimelineLite in the previous GreenSock tutorials.

But lets be honest, how often do you need to move a box on your real life projects?

In this tutorial you’ll learn how to create a simple image slider using GreenSock’s TweenLite and TimelineLite.

The effects and animations in this tutorial are inspired by 2 great websites – heartkids.co.nz and fixedgroup.com, credit to the talented teams behind them.

GreenSock Tutorial: How To Create A Simple Image Slideshow

What you’ll learn

  • How to structure HTML and CSS for a fullscreen layout
  • How to play GreenSock timelines based on user interaction
  • How to create a cool tilt effect

VIEW DEMO DOWNLOAD FILES

Video Screencast

Do you prefer to watch videos instead of following written tutorials? You can watch this tutorial on my YouTube Channel.

VIEW SCREENCAST

Ready to get your hands dirty with GreenSock?

Note: This tutorial is aimed at designers and developers with a working HTML/CSS knowledge and the primary focus is to learn how to use GreenSock in a real world project.

I also assume that you already know what GreenSock is.

1. HTML – Setup A Structure For Fullscreen Image Slideshow

Firstly we’ll create our structure in the index.html.

<div class="bcg">
  <div class="hero">

    <!-- Top part -->
    <div class="top">

      <a href="https://ihatetomatoes.net/blog/" class="logo"><img src="img/icon-logo.png" /></a>

      <!-- Slide 1 top content -->
      <div class="homeSlide slide01 active">

        <h1>Green<span>Sock</span> Tilt Effect</h1>

      </div>

      <!-- Slide 2 top content -->
      <div class="homeSlide slide02">

        <h1>Split Screen Slider</h1>

      </div>

      <!-- Slide 3 top content -->
      <div class="homeSlide slide03">

        <h1>Slide 3 Title</h1>

      </div>

    </div><!-- /Top part -->

    <!-- Bottom part -->
    <div class="bottom">

      <!-- Slide 1 bottom content -->
      <div class="homeSlide slide01 active">

        <p>
          Move your mouse to see the tilt effect in action.<br />
          <em>Your current position is: <strong>0, 0</strong></em>
        </p>

      </div>

      <!-- Slide 2 bottom content -->
      <div class="homeSlide slide02">

        <p>
          Another slide description goes here.
        </p>

      </div>

      <!-- Slide 3 bottom content -->
      <div class="homeSlide slide03">

        <p>
          Another slide description goes here.
        </p>

      </div>

    </div><!-- /Bottom part -->

    <!-- Fancy divider with gradient backgound -->
    <div class="divider"></div>

  </div>

  <!-- Prev/Next Navigation -->
  <div id="slideNav">
    <ul>
      <li class="slideNavPrev">
        <a href="#" title="Go to previous slide">
          <span class="ico ico-up">↓</span>
        </a>
      </li>
      <li class="slideNavNext">
        <a href="#" title="Go to next slide">
          <span class="ico ico-down">↑</span>
        </a>
      </li>
    </ul>
  </div>

</div>

We’ll create a fullscreen container .bcg and inside of it .hero container that will be used for the tilt effect.

.top and .bottom are 2 containers with position: absolute, both have the left and right offset 30px, but their bottom and top offset is set to 50%.

This makes them cover only half of the screen. Here is the visual image of our html layout.

GreenSock Tutorial: How To Create A Simple Image Slideshow

2. CSS – Create A Fullscreen Layout

Copy and paste the CSS for our sturcture into the main.css.

.logo {
  position: absolute;
  top: 50px;
  left: 50%;
  -webkit-transform: translateX(-50%);
      -ms-transform: translateX(-50%);
          transform: translateX(-50%);
  z-index: 6;
  opacity: 0.3;
}

.bcg {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

h1 {
  color: #ffffff;
  font-weight: 300;
  position: absolute;
  bottom: 0%;
  width: 100%;
  margin: 0 0 20px 0;
  font-size: 60px;
  text-align: center;
}

.hero {
  position: absolute;
  height: 100%;
  width: 100%;
}

.top {
  overflow: hidden;
  position: absolute;
  top: 30px;
  left: 30px;
  right: 30px;
  bottom: 50%;
  border: 1px rgba(255, 255, 255, 0.2) solid;
  border-width: 1px 1px 0 1px;
}

.homeSlide {
  position: absolute;
  width: 100%;
  height: 100%;
}
.homeSlide.slide01 {
  background: url(../img/img_clouds-top.jpg) no-repeat bottom center;
  background-size: cover;
}
.bottom .homeSlide.slide01 {
  background: url(../img/img_clouds-bottom.jpg) no-repeat top center;
  background-size: cover;
}
.homeSlide.slide02 {
  background: url(../img/img_clouds-top2.jpg) no-repeat bottom center;
  background-size: cover;
}
.bottom .homeSlide.slide02 {
  background: url(../img/img_clouds-bottom2.jpg) no-repeat top center;
  background-size: cover;
}
.homeSlide.slide03 {
  background: url(../img/img_clouds-top3.jpg) no-repeat bottom center;
  background-size: cover;
}
.bottom .homeSlide.slide03 {
  background: url(../img/img_clouds-bottom3.jpg) no-repeat top center;
  background-size: cover;
}

.divider {
  z-index: 3;
  position: fixed;
  top: 50%;
  margin-top: -40px;
  left: -200px;
  right: -200px;
  height: 40px;
  background: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0.5) 0%, rgba(34, 34, 34, 0) 100%);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.5) 0%, rgba(34, 34, 34, 0) 100%);
}

.bottom {
  overflow: hidden;
  position: absolute;
  top: 50%;
  left: 30px;
  right: 30px;
  bottom: 30px;
  border: 1px rgba(255, 255, 255, 0.2) solid;
  border-width: 0 1px 1px 1px;
}
.bottom p {
  font-size: 20px;
  color: #ffffff;
  font-weight: 300;
  opacity: 0.7;
  text-align: center;
}
.bottom a {
  color: #fff;
}

#slideNav {
  z-index: 5;
  position: fixed;
  right: 50px;
  top: 50%;
  width: 50px;
  -webkit-transform: translateY(-50%);
      -ms-transform: translateY(-50%);
          transform: translateY(-50%);
}

#slideNav ul {
  list-style: none;
  color: #ffffff;
  font-size: 13px;
  text-align: center;
  margin: 0;
  padding: 0;
}

#slideNav li {
  width: 50px;
  height: 50px;
  line-height: 50px;
  background-color: rgba(0, 0, 0, 0.7);
  margin-bottom: 1px;
}

#slideNav a {
  display: block;
  width: 50px;
  height: 50px;
  position: relative;
  overflow: hidden;
  text-decoration: none;
  color: #ffffff;
}

.divider is a 40px tall container centered on the page and sitting inside of the .hero on top of .top and .bottom.

Lets now break down the top part of our slider.

It contains 3 homeSlide containers with a unique class slide01, slide02 and slide03 and a unique background image.

If you save the page now and preview it in a browser you’ll see the slide03 sitting on top.

That’s ok, we’ll use GreenSock later to hide all slides apart from the .active slide.

GreenSock Tutorial: How To Create A Simple Image Slideshow

Similar structure, classes and styles are applied to the .bottom half of our slider.

Now it’s time to start tweening with GreenSock.

3. Go To The Next Slide

GreenSock Tutorial: How To Create A Simple Image Slideshow

All the interactivity will happen in the main.js, open the file and keep adding the following code.

Don’t worry if you’ll make a mistake, the whole code is at the bottom of this part of the tutorial.

3.1 Create variables

// Setup variables
var $activeSlide = $(".active"),
    $homeSlide = $(".homeSlide"),
    $slideNavPrev = $(".slideNavPrev"),
    $slideNavNext = $(".slideNavNext")
    $slideNavPrevA = $(".slideNavPrev a"),
    $slideNavNextA = $(".slideNavNext a"),
    $hero = $(".hero");

These variables are all the elements on the page that we will be interacting with. We are simply targeting each element by their class or tag eg. ".slideNavNext a".

$homeSlide are all the moving parts of our image slideshow, these are both top and bottom parts of all 3 slides.

$activeSlide is the currently active slide.

If you are a beginner or want to refresh your jQuery knowledge, read this jQuery Datatypes and Selectors guide.

3.2 Hide all inactive slides on page load

// Init function that run on page load
function init(){

  // Hide all slides apart from the active one
  TweenLite.set($homeSlide.not($activeSlide), {autoAlpha: 0});

  // Disable arrow down on page load
  TweenLite.set($slideNavPrev, {autoAlpha: 0.2});

}

// Run Init function
init();

The first tween inside of the init function will hide all slides apart from the one with a class .active.

The second tween will fade out the arrow pointing down because at that moment there is no previous slide.

3.3 Run goToNextSlide() function on click

GreenSock Tutorial: How To Create A Simple Image Slideshow

Now we’ll setup a function that we want to be triggered when the user clicks on the $slideNavNext button.

Add this after the init(); and refresh the page.


// Go to next slide
function goToNextSlide(){

  alert('Go to next');

}

// Navigation click - go to the Next Slide
$slideNavNext.click(function (e) {
  e.preventDefault();

  goToNextSlide();

});

You’ll see that a click on the arrow up now triggers an alert popup with “Go to next” message.

3.4 Animate The Right Slides

We can remove the alert inside of goToNextSlide() and update the click function to pass through the slideOut and slideIn.

$slideNavNext.click(function (e) {
  e.preventDefault();

  var slideOut = $('.homeSlide.active'),
      slideIn = $('.homeSlide.active').next('.homeSlide');

  goToNextSlide(slideOut, slideIn);

});

Everytime the user clicks on the navigation, we want to pass the right slideOut and slideIn elements.

This means that on a page load the slideOut is .slide01 and slideIn is the next slide .slide02.

GreenSock Workshop - Premium GreenSock Tutorials - Sign Up Now!

3.5 Go To Next Slide – GreenSock Timeline

Now we’ll update the goToNextSlide function to accept the 2 new parameters.

// Go to next slide - pass 2 parameters - slideOut and slideIn
function goToNextSlide(slideOut, slideIn){
  var tl = new TimelineLite(),
    slideOutH1 = slideOut.find('h1'),
    slideOutP = slideOut.find('p'),
    slideInH1 = slideIn.find('h1'),
    slideInP = slideIn.find('p'),
    index = slideIn.index(),
    size = $('.top .homeSlide').length;

  // go to the next slide timeline

}

We are also setting up new variables inside of this function.

tl is a new GreenSock TimelineLite that will be used for our animation sequence.

Then we are getting h1 and p of both slideIn and slideOut so we can animate them in different directions.

index and size will be used for a few if statements later on.

Note: paste the following code inside of the goToNextSlide function, where indicated by the comment.


  // go to the next slide timeline
  tl
	// move the new slide (the one about to enter viewport) out of the viewport and add class active
	.set(slideIn, {y: '100%', autoAlpha: 1, className: '+=active'})

	// remove class active from the currently active slide (slideOut)
	.set(slideOut, {className: '-=active'})

	// animate H1 and p of the active slide up and fade them out
	.to([slideOutH1,slideOutP], 0.3, {y: '-=15px', autoAlpha: 0, ease:Power3.easeInOut}, 0)

	// animate active slide up (out of the viewport)
	.to(slideOut, 0.5, {y: '-100%', ease:Power3.easeInOut}, 0)

	// animate new slide up (from out of the viewport)
	.to(slideIn, 0.5, {y: '-=100%', ease:Power3.easeInOut}, 0)

	// animate H1 and P of the new slide up and fade them in
	.fromTo([slideInH1,slideInP], 0.3, {y: '+=20px', autoAlpha: 0}, {autoAlpha: 1, y: 0, ease:Power1.easeInOut}, 0.3);

Read the comments above each of the tweens to see what they are doing.

Firstly we are positioning the new slide slideIn out of the viewport and adding .active to it and removing class from the slideOut.

The main image tweens are highlighted in green and both of them are happening at the same time as the text is fading out.

They all start at the absolute beginning of our timeline.

Read more about positioning of tweens on the GreenSock timeline.

If you are following correctly, you’ll see that we have an issue when we click on the next arrow on the third slide, we are going to a blank slide.

3.6 Prevent Going To A Blank Slide

To avoid the transition into a blank slide (essentially there is no next slide when we are on the .slide03), we can simply wrap our timeline into an if statement.

if(slideIn.length !== 0){
  // go to the next slide timeline
  tl
	// Keep tweens, just wrap the timeline in the highlighted if statement
}

// Fade out arrow up and fade in arrow down

This will check whether there is a next slide and if there is, we will play our timeline.

3.7 Fade In/Out Navigation Arrows

GreenSock Tutorial: How To Create A Simple Image Slideshow

To make this function complete we will fade out the arrow up on the last slide and ‘enable’ arrow down on the first click.

// Fade out arrow up and fade in arrow down 

// Fade in arrow down
TweenLite.set($slideNavPrev, {autoAlpha: 1});

// Fade out arrow up on last slide
if(index === size){
  TweenLite.to($slideNavNext, 0.3, {autoAlpha: 0.2, ease:Linear.easeNone});
}

index returns the index value of the new slide (.slide01 = 0, .slide02 = 1 etc) and size is a total count of slides in our case 3.

Both of these variables return 3 on the last slide, that is when we want to fade out the arrow up.

This was a beast but creating the opposite direction function will be much easier.

3.8 All together

To make sure you’ve added the code to the right places, here is the complete code for the transition to next slide.

// Go to next slide - pass 2 parameters - slideOut and slideIn
function goToNextSlide(slideOut, slideIn){
  var tl = new TimelineLite(),
	slideOutH1 = slideOut.find('h1'),
	slideOutP = slideOut.find('p'),
	slideInH1 = slideIn.find('h1'),
	slideInP = slideIn.find('p'),
    index = slideIn.index(),
    size = $('.top .homeSlide').length;

	if(slideIn.length !== 0){

		// go to the next slide timeline
		tl
			// move the new slide (the one about to enter viewport) out of the viewport and add class active
			.set(slideIn, {y: '100%', autoAlpha: 1, className: '+=active'})
			// remove class active from the currently active slide (slideOut)
			.set(slideOut, {className: '-=active'})
			// animate H1 and p of the active slide up and fade them out
			.to([slideOutH1,slideOutP], 0.3, {y: '-=15px', autoAlpha: 0, ease:Power3.easeInOut}, 0)
			// animate active slide up (out of the viewport)
			.to(slideOut, 0.5, {y: '-100%', ease:Power3.easeInOut}, 0)
			// animate new slide up (from out of the viewport)
			.to(slideIn, 0.5, {y: '-=100%', ease:Power3.easeInOut}, 0)
			// animate H1 and P of the new slide up and fade them in
			.fromTo([slideInH1,slideInP], 0.3, {y: '+=20px', autoAlpha: 0}, {autoAlpha: 1, y: 0, ease:Power1.easeInOut}, 0.3);

	} 

	// Fade out arrow up and fade in arrow down 

	// Fade in arrow down
	TweenLite.set($slideNavPrev, {autoAlpha: 1});

	// Fade out arrow up on last slide
	if(index === size){
	  TweenLite.to($slideNavNext, 0.3, {autoAlpha: 0.2, ease:Linear.easeNone});
	}

}

// Navigation click - go to the Next Slide
$slideNavNext.click(function (e) {
  e.preventDefault();

  var slideOut = $('.homeSlide.active'),
      slideIn = $('.homeSlide.active').next('.homeSlide');

  goToNextSlide(slideOut, slideIn);

});

4. Go To The Previous Slide

The function to control the movement in the opposite direction looks almost identical.

GreenSock Tutorial: How To Create A Simple Image Slideshow

We will call this function goToPreviousSlide() and will also pass through the correct slideOut and slideIn to it.

// Go to previous slide - pass 2 parameters - slideOut and slideIn
function goToPreviousSlide(slideOut, slideIn){

  var tl = new TimelineLite(),
    slideOutH1 = slideOut.find('h1'),
    slideOutP = slideOut.find('p'),
    slideInH1 = slideIn.find('h1'),
    slideInP = slideIn.find('p'),
    index = slideIn.index(),
    size = $('.top .homeSlide').length;

  if(slideIn.length !== 0){

    // go to the previous slide timeline
    tl
      // move the new slide (the one about to enter viewport) out of the viewport (to the top)
      .set(slideIn, {y: '-100%', autoAlpha: 1, className: '+=active'})
      // remove class active from the currently active slide (slideOut)
      .set(slideOut, {className: '-=active'})
      // animate H1 and p of the active slide down and fade them out
      .to([slideOutH1,slideOutP], 0.3, {y: '+=15px', autoAlpha: 0, ease:Power3.easeInOut}, 0)
      // animate active slide down (out of the viewport)
      .to(slideOut, 0.5, {y: '100%', ease:Power3.easeInOut}, 0)
      // animate new slide down (from out of the viewport)
      .to(slideIn, 0.5, {y: '+=100%', ease:Power3.easeInOut}, '-=0.5')
      // animate H1 and P of the new slide down and fade them in
      .fromTo([slideInH1,slideInP], 0.3, {y: '-=20px', autoAlpha: 0}, {autoAlpha: 1, y: 0, ease:Power1.easeInOut}, 0.3);

  }

  // Fade in arrow up
  TweenLite.set($slideNavNext, {autoAlpha: 1});

  // Fade out arrow down on first slide
  if(index === 1){
    TweenLite.to($slideNavPrev, 0.3, {autoAlpha: 0.2, ease:Linear.easeNone});
  }

}

// Navigation click - go to the Previous Slide
$slideNavPrev.click(function (e) {
  e.preventDefault();

  var slideOut = $('.homeSlide.active'),
      slideIn = $('.homeSlide.active').prev('.homeSlide');

  goToPreviousSlide(slideOut, slideIn);

});

All the tweens within this timeline have the values reversed, in other words what was animating from the bottom is now coming from the top.

We are triggering this function when the user clicks the arrow pointing down $slideNavPrev.

5. Adding A Tilt Effect

Now we have a fully functionally fullscreen slideshow, but we will add one more subtle effect to it.

GreenSock Tutorial: How To Create A Simple Image Slideshow

We will tilt the whole .hero container based on the current mouse position.

Add this to the main.js:

// Mouse move tilt effect
$(document).mousemove(function(event){

	// Detect mouse position
	var xPos = (event.clientX/$(window).width())-0.5;
	var yPos = (event.clientY/$(window).height())-0.5;

	// Tilt the hero container
	TweenLite.to($hero, 0.6, {rotationY:5*xPos, rotationX:5*yPos, ease:Power1.easeOut, transformPerspective:900, transformOrigin:"center"});

	// Update text on the page with the current mouse position
	$(".bottom strong").text(event.pageX + ", " + event.pageY);
});

Inside of the .mousemove function, we are firstly detecting the current mouse position.

Based on the mouse position and the browser window width, the xPos returns value -0.5 when we are hovering over the left edge of the viewport and 0.5 when we are hovering over the right edge, it returns zero right in the middle.

The same calculation applies to the yPos.

Here is a visual indication of the rotation calculation.

GreenSock Tutorial: How To Create A Simple Image Slideshow
Then we are rotating the .hero container using a simple .to tween – rotationY:5*xPos, rotationX:5*yPos.

Play with the rotation multiplier 5* and the transformPerspective values to get the desired effect. Remember subtle effects are usually the most effective.

Note: Please also consider your target audience before implementing this tilt effect into your projects. Animate responsibly.

Conclusion

There you have it, a simple fullscreen image slideshow created using GreenSock’s TweenLite and TimelineLite.

VIEW DEMO DOWNLOAD FILES

I hope this GreenSock tutorial showed you how you could create your own custom image slideshows using this amazing animation platform.

What do you think about the final demo? Did I forget to explain something in more detail or do you have any other GSAP related questions?

Let me know in the comments below and don’t forget to subscribe to my YouTube Channel for a screencast version of this tutorial.

Other GreenSock Learning Resources

Share this

TwitterFacebookGoogle+

Want To Learn More About GreenSock?

Join me in the GreenSock Workshop and learn how to build 3 interactive projects from start to finish.

Visit GreenSock Tutorials to see the SVG Lab project live.

Download Free Toolkit

All you need to know to get started with GreenSock and ScrollMagic, in one single package. Straight into your inbox.

100% Privacy. Guaranteed! Powered by ConvertKit

19 thoughts on “GreenSock Tutorial – How To Create A Simple Image Slideshow

  1. Simon

    Awesome stuff, as always Petr. Keep ’em coming, it’s a great way for all of us to consolidate our growing GSAP skills with real case scenarios.

    I love the attention to details you put in making these explainer images with dimensions and values. Very well crafted, makes it very clear.

    In other words, you rock! 🙂

    Reply
    1. Petr Tichy Post author

      Thanks Simon, I am trying to create these images to make it easier to understand the code snippets. Glad to hear that they work:) Thanks heaps for your support Simon!

      Reply
  2. Eneas

    Hi Petr!

    I found your tutorial really useful and the result is amazing, but I am having performance issues, when tilting the image, this moves really slowly and feels no fluid at all.
    Have that ever happened to you?

    Reply
  3. Oliver Chalmers

    Petr this is great, thank you so much. I was wondering – how would we go about making this an endless loop, as in if you were at the beginning and clicked previous it would go to the end and similarly for the last slide clicking and going back to the beginning?

    Again thanks so much, just signed up to your mailing list as a result!

    Best,
    Oliver

    Reply
    1. Petr Tichy Post author

      Hey Oliver, that would be quite simple.

      Here’s a CodePen with the infinite loop.

      All you have to do is to add an if statement checking if you are on the first or last slide, and pass the right slide to the function, eg.:

        if(slideOut.hasClass('slide01')){
          slideIn = $('.slide03');
        }
      

      Hope that helps, and don’t forget to confirm you email, until then you are still not subscribed.

      Cheers
      Petr

      Reply
      1. Oliver Chalmers

        Hey Petr,

        I’ve been having so much fun playing around with this it’s fantastic so thanks again. Something i’m having trouble doing is creating the logic for the slider to go back to the beginning when at the end and visa versa for going back when at the beginning. I know you had previously posted this little snippit below –

        if(slideOut.hasClass('slide01')){
          slideIn = $('.slide03');
        }
        

        which is perfect for if there are 3 slides, but I was hoping you’d be able to help with the logic to work it out regardless of the number of slides. I’m thinking you have to determine the length of the list using .length and then pass that against the current .index of the .homeSlide – but I can’t seem to get it to work! Any chance you could help out here if you have any spare seconds? Thanks so much!

        Oliver

        Reply
        1. Oliver

          Hey Petr,

          Just wondering if you had any ideas on the above request? Sorry to ask again i’ve been trying to figure this out for ages!

          Thanks again for all your work.

          Oliver

          Reply
          1. Petr Tichy Post author

            Hi Oliver,
            if you simply use the CSS :last-child selector, it should always return the last slide, no matter how many slides are in your slideshow.

            if(slideOut.hasClass('slide01')){
                slideIn = $('.homeSlide:last-child');
            }
            

            Hope that helps.

  4. Rana Hussain

    Hi Petr,

    I love your tutorial I was looking for this kind of slider for months and months. You are rock. I would like to make some changes if it is possible I would like to load next slide with jquery $.load method because every slider have a subpages so when we click on link new page will load with the sliding effect with $.load method.
    How can I achieve this effect. I hope it makes sense to you.
    Here is a reference site. I want to achieve same effect.
    http://nicolas-bussiere.fr

    many thanks.

    Reply
    1. Petr Tichy Post author

      Hi Rana, thanks for the cool reference site, I see what you are trying to do. The loading of additional content via AJAX is outside of the scope of this tutorial but I might create one in the future.

      Reply
      1. Rana Hussain

        Thanks Petr for your reply.
        I will really really appreciate if you will make this tutorial.

        Many thanks

        Reply
  5. Rana Hussain

    Hi Petr,
    I would like to add some more functionality in this slider, however I need your help if possible. I would like to add mouse wheel control in this slider when user scroll mouse wheel slide should change one by one with mouse wheel interaction. When slider on last slide mouse wheel stop to move slides. To better understand what I want to achieve please visit this website
    http://nicolas-bussiere.fr
    you will get the idea.

    I asked you before one question how to load slider through AJAX. I achieved this effect. You can see live demo here. When you click on heading link it will take you another page where the slider starts.

    http://magtechpro.work/ab/index6.html

    Thanks in advance

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.