Jump to content
GreenSock

Understanding GSAP Keyframes


| GreenSock
26746

If you find yourself writing multiple tweens to animate one target, it may be time to reach for keyframes. Keyframes are a great way to move a target through a series of steps while keeping your code concise.

Take a repetitive timeline like the one below — It can be simplified down nicely to fit into one tween:

// timeline
let tl = gsap.timeline();
tl.to(".box", {
    x: 100
  })
  .to(".box", {
    y: 100
  })
  .to(".box", {
    x: 0
  })
  .to(".box", {
    y: 0
  });

// Array-based keyframes
gsap.to(".box", {
  keyframes: {
    x: [0, 100, 100, 0, 0],
    y: [0, 0, 100, 100, 0],
    ease: "power1.inOut"
  },
  duration: 2
});


We like to think of keyframes as a sub-timeline nested inside a tween. There are a few different ways to write keyframes. If you're a visual learner, check out this video.
 

 

Keyframe Options

Object keyframes - v3.0

This keyframes syntax lets you pass in an Array of vars parameters to use for the given target(s). Think of them like a sequence of .to() tween vars. You can use a delay value to create gaps or overlaps.

The default per-keyframe ease is linear which you can override in individual keyframes. You can also apply an ease to the entire keyframe sequence.

gsap.to(".elem", {
 keyframes: [
  {x: 100, duration: 1, ease: 'sine.out'}, // finetune with individual eases
  {y: 200, duration: 1, delay: 0.5}, // create a 0.5 second gap
  {rotation: 360, duration: 2, delay: -0.25} // overlap by 0.25 seconds
 ],
 ease: 'expo.inOut' // ease the entire keyframe block
});

 

Percentage keyframes - v3.9

This familiar syntax makes porting animations over from CSS a breeze! Instead of using delays and duration in the keyframe object, you specify an overall duration on the tween itself, then define the position of each keyframe using percentages.

To be consistent with CSS behaviour, the default per-keyframe ease is power1.inOut which generally looks quite nice but you can override this in individual keyframes or on all keyframes using easeEach.

gsap.to(".elem", {
 keyframes: {
  "0%":   { x: 100, y: 100},
  "75%":  { x: 0, y: 0, ease: 'sine.out'}, // finetune with individual eases
  "100%": { x: 50, y: 50 },
   easeEach: 'expo.inOut' // ease between keyframes
 },
 ease: 'none' // ease the entire keyframe block
 duration: 2,
})

 

Simple Array-based keyframes - v3.9

Just define an Array of values and they'll get equally distributed over the time specified in the tween.

The default per-keyframe ease is power1.inOut, but you can override this by using easeEach. The Arrays do not need to have the same number of elements.

gsap.to(".elem", {
 keyframes: {
  x: [100, 0, 50],
  y: [100, 0, 50]
  easeEach: 'sine.inOut' // ease between keyframes
  ease: 'expo.out' // ease the entire keyframe block
 },
 duration: 2,
})

 

Easing keyframes

Easing is integral to animation and keyframes give you a huge amount of flexibility.

Percentage keyframes and Simple keyframes allow you to control the ease between each of the keyframes with easeEach.

With Object keyframes and Percentage keyframes you can drill down and add different eases into individual keyframes.

You can even combine multiple easing properties, keyframes and normal tween values. 🤯

gsap.to(".box", {
  keyframes: {
    y: [0, 80, -10, 30, 0],
    ease: "none", // <- ease across the entire set of keyframes (defaults to the one defined in the tween, or "none" if one isn't defined there)
    easeEach: "power2.inOut" // <- ease between each keyframe (defaults to "power1.inOut")
  },
  rotate: 180,
  ease: "elastic", // <- the "normal" part of the tween. In this case, it affects "rotate" because it's outside the keyframes
  duration: 5,
  stagger: 0.2
});

Keyframe tips

Both the Object keyframes and the Percentage keyframes behave similarly to tweens, so you can leverage callbacks like onStart and onComplete.

gsap.to(".elem", {
 keyframes: [
  {x: 100, duration: 1},
  {y: 200, duration: 1, onComplete: () => { console.log('complete')}},
  {rotation: 360, duration: 2, delay: -0.25, ease: 'sine.out'}
 ]
});

gsap.to(".elem", {
 keyframes: {
  "0%":   { x: 100, y: 100},
  "75%":  { x: 0, y: 0, ease: 'power3.inOut'},
  "100%": { x: 50, y: 50, ease: 'none', onStart: () => { console.log('start')} }
 },
 duration: 2,
})

We hope this has helped you get your head around keyframes - if you have any questions pop over to our forums.

Happy tweening!

  • Like 5
  • Thanks 1

Get an all-access pass to premium plugins, offers, and more!

Join the Club

When is the last time you worked on something you love? Go animate something cool and then share it with us.

- Team GreenSock



User Feedback

Recommended Comments

Can you tell me please what script you are using for animation? It's not running on my code.

I have put minified.gsap.min,  and tried a source from CODE pen: gsap-latest-beta.min.js.

I tried each of them separately and didn't work. TY

Link to comment
Share on other sites

Hi @stayleess. It's difficult to troubleshoot blind - we'd be happy to help if you can post your question in the forums along with a minimal demo that clearly shows the problem. As it stands now, though, it's impossible for us to know what's going on in your project or why you can't get things to work. 

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

×