Jump to content


Responsive slider timeline

Go to solution Solved by Shaun Gorneau,

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi Folks,


Sorry for the nuisance, but boy am I rusty with GSAP.  Besides, it's got a lot of cool new features!


My project is quite simple though.  I need to make an image viewer that scrolls pictures horizontally by control of a draggable slider.  It needs to have these requirements:

  • scroll from first to last of what will be a dynamically created set of image divs
  • when the user releases the slider handle,  the group should center up the image closest to the center
  • continue to work (centering up) responsively for different sized screens

I stole a bunch of stuff from the examples found here, but have a couple of questions.  Please check my CodePen. I have a single timeline that is using xPercent to scroll to the end of the content div that holds the multiple image divs.  


Q1: Unfortunately it finishes outside the container and I would like it to stop with the last image div (which is the right side of the content div) at the right end of it's container. So the container will never be empty. 


Q2: I am planning to drop some Position labels  at the center of each image, and write a function on release of the slider for the timeline to float to the closest one.  The math is easy, because the duration of the timeline in seconds is equal to the number of images, so I can start at 0.5, and push each one out +1 sec till the end.  Does this make sense or is there a better method?


And finally, why is my jquery-ui slider not updating correctly?  I have all of the external CSS and JS files linked to the Codepen, but the slider button updates position very sporadically.


Any help is hugely appreciated.  Thanks,

-- Pawley


See the Pen QpGKjr by PawleyBoboli (@PawleyBoboli) on CodePen

Link to comment
Share on other sites

While I'm not using swipe interaction on this, it might be helpful.


See the Pen RpKKmN?editors=0010 by sgorneau (@sgorneau) on CodePen


One big difference here is I'm not using a timeline ... I'm using Tweens to move in either direction +=/-= the width of one "slide" and jumping to initial and (calculated) end states when wrapping. I say calculated end state because, not being a timeline, the end state is the width of a slide * the number of slides.


These slider slide sizes and end position are recalculated when the browser resizes.


Essentially, what I'm doing here is the following


  • The markup output from the CMS is a straight-forward set of <div>s, one for each image associated with a featured blog post (you can see this in the HTML window of the pen)
  • Some fairly straightforward styling to get them setup in a horizontal strip
  • Javascript (in this case using jQuery) to take the last two blog posts and prepend them to the strip and take the first two blog posts and append them to the the strip. This is to solve the problem of empty space at the bounds of the original set to make a "seamless" trip around
  • As the user advances "forward", when the first appended slide is animated in, the slider resets to the initial position of the timeline
  • As the user advances "backward", when the last prepended slide is animated in, the slider jumps to the calculated end position

To explain, imagine that the markup initially setup the slides as


1 2 3 4 5


The javascript then prepends/appends


-4 -5 1 2 3 4 5 +1 +2


The slide show "displays"


-5 1 2 


to start


as the user advances forward they would see in order


-5 1 2 > 1 2 3 > 2 3 4 > 3 4 5 > 4 5 -1 .... if advanced forward from here, the animation would reveal 5 -1 -2 and then immediately jump to -5 1 2 (the initial state)


In the reverse, from the initial state


-5 1 2 back to -4 -5 1 would animate in and then jump to 4 5 -1 (the end state)

  • Like 5
Link to comment
Share on other sites

Wow Shaun,

that's a really great-looking slider, and cleverly coded.  Unfortunately for me, having a draggable scrollbar to move through the timeline is a design-requirement by the client.  There are plenty of techniques you are using that will come in handy for other parts of my project, however, so thanks tons for sharing this with me.


I dug around ald603's "GSAP image slider" post from a few days ago, forking the Codepen that was created, and was able to add a scrollbar to that timeline to control it.  This works as I would like, but my snap-to-next/previous label isn't perfect.  The functionality I'd like is if someone drags the slider part way between two images and releases it, the slider and controller will float toward the nearest label.  So if you drag past halfway to the next image and let go, the timeline moves forward to the next image, but if you let go less than halfway to the next image, it moves back to the previous image.


My attempt kind of works, but not exactly.  You have to get like 3/4 way near the next or previous label for it to not go back to the previous one.  I think my problem is somewhere in the stop function of my controler:

stop:function() {
      var currentTime = _tl.time()
      var timeBetween = _tl.getLabelTime( _tl.getLabelAfter()) - _tl.getLabelTime( _tl.currentLabel());
      var midPoint = _tl.getLabelTime( _tl.currentLabel()) + (timeBetween/2);
      console.log("Mid point between labels is: " + midPoint + "   current time: " + currentTime);
      if (currentTime >= midPoint) {
        // go to the next label
        _tl.tweenTo( _tl.getLabelAfter() );
      } else {
        _tl.tweenTo( _tl.currentLabel() );

Is there a better way to do this?  Here is my forked Codepen so you can see it in action:  

See the Pen bqgBzX?editors=0010 by PawleyBoboli (@PawleyBoboli) on CodePen


Again, thanks so much for any input,


Link to comment
Share on other sites

Ok, understood about the need for a timeline. 


To address the "Q1: Unfortunately it finishes outside the container ... " I've forked your pen and modified the CSS quite a bit so you don't have to rely on calculating and setting a width for the container ... CSS will simply allow it to layout and then we can just "grab" the width. This will happen no matter how many boxes are placed within.


I've modified your JS only a bit.


All modifications have notes as to why I did something (pretty sure I commenting everything), so it should be pretty clear.


See the Pen bqgzmJ?editors=0110 by sgorneau (@sgorneau) on CodePen


As for "when the user releases the slider handle,  the group should center up the image closest to the center" ... that can certainly be done by animating to multiples of a box width ... but the current layout doesn't really make use of a "center position" as it currently displays approx 3.75 boxes.


[Edit] My last statement was in regard to your first pen, I hadn't realized there was a second :)

  • Like 1
Link to comment
Share on other sites

  • Solution

I've forked the pen above to introduce "snap points".


What I've done is calculated the width of 1 tile divided by the width of the animated container to get a decimal representing the increment on a 0 to 1 point scale (which is appropriate for the timeline) for each tile movement (just multiply that number by 100 for the 0-100 scale value the jqueryui slider uses). I also have an array of "snap points" built using that increment decimal times `var i` in a loop up to the number of tiles in the animated container; which is the total number of tiles minus the number visible at any given time ... in this case, 9 total with 3 visible ... that gives us 6 snap points. Lastly, I have a function that looks through an array (our snap points array in this case) and finds the closest value it contains compared to any number passed to it. So, when the UI slider is done "sliding", its position/100 is passed to this function, the function looks through the snap points array to find the closest value, that value is returned, the timeline is animated to that value and the slider's position is animated to that value*100.


Important thing to note here ... I have set `ease: Power0.easeNone` (line 44) on the timeline ... easing will interfere with the 0 - 1 scale with regard to equal, incremental chunks for the snap points. I am, however using an ease when tweening the timline progress to the snap point value (line 71).


See the Pen mWRZob by sgorneau (@sgorneau) on CodePen

  • Like 4
Link to comment
Share on other sites

Wow Shaun, you're a champ!


This is the functionality I was looking for as far as the snapping goes and it works much better than my attempt.  Besides that, I am totally exposed for my lack of CSS skilz/understanding.  Sometimes, half my battles with JS and GSAP are due to weaknesses in my CSS.  


The learning continues.  Thanks tons!



  • Like 3
Link to comment
Share on other sites

Hi Shaun,


My slider project is working out great.  Thanks for your help.  The slider is too small to manage on small screen like phones, so I have added next/previous buttons at the CSS media break for phones and turn off the display for the slider.  Attached are pictures of what the final looks like, and here is a new CodePen with my current edits:  

See the Pen aJVMyr by PawleyBoboli (@PawleyBoboli) on CodePen


I stole your function for the snapping slider and adapted it for the next/prev buttons.  The previous button works fine, but sometimes the next button goes backwards, especially if you click it repeatedly.  Also, my project will have 20 or more panels, so the differences between steps in the timeline will be getting smaller as I add more panels.  Is there a way to make sure the next button doesn't go backwards?  Thanks for any insight.






Link to comment
Share on other sites

Hi Folks,


I have altered my next button function to iterate through the array of snap points backwards, and that seems to work better, but not 100% of the time.  This at least never goes backwards when you click the forward button, but on occasion, it will skip a panel and jump ahead 2.  In the codepen, it seems do this this less than in my actual project, but it will still do it there as well.


the codepen is here: 

See the Pen ?editors=1010 by PawleyBoboli (@PawleyBoboli) on CodePen

 and the revised next button function is this:

function tlNext(arr, target) {
    if (!(arr) || arr.length === 0)
        {return null;}
    if (arr.length === 1)
		{return arr[0];}

    for (var i = arr.length-1; i >= 0; i--) {
        if (arr[i] <= target + 0.01) {
            return arr[i+1];
		} else if (arr[i] < target) {
			return arr[i+2];

When I put a break into this and look at the values for target and the array of snapping points, the times I am getting a 2 -panel jump is when the snap point in the array is 0.9 but the target (tl.progress()) is 0.9000000000000001.  I put in a buffer of 0.01 to accommodate for that, but now if you click the next button quickly, CodePen is saying there's an  Infinite loop found on line 0.  and stops working - even though I get no errors in my actual project in Chrome or Firefox (still need to test elsewhere).


Any ideas how to make this button go to the next snap point in the timeline without errors?  Kinda weird why the reverse button works great, but the fwd one does not.


Thanks for any insight.



Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.