Grow your CSS skills. Land your dream job.

Improving UI Animation Workflow with Velocity.js

Published by Chris Coyier

The following is a guest post by Julian Shapiro. Julian recently released Velocity.js, a more performant jQuery replacement for .animate(). He recently wrote about how JavaScript animations can be so fast over on David Walsh's blog, a topic we've covered here as well. In this article, Julian introduces Velocity.js itself.

Velocity.js is a jQuery plugin that re-implements jQuery's $.animate() function to produce significantly higher performance (making Velocity also faster than CSS transitions in many cases) while including several new features to improve animation workflow.

In 7Kb (zipped), Velocity includes all of $.animate()'s features while also packing in transform animation, looping, class animation, and scrolling. In short, Velocity is designed to be the best of jQuery, jQuery UI, and CSS transitions.

Velocity works everywhere — back to IE8 and Android 2.3. Further, since Velocity's syntax is identical to $.animate()'s, none of your page's code needs to change.

The goal of Velocity is to be a leader in DOM animation performance and convenience. This article focuses on the latter. To learn more about the former, refer to Velocity's performance comparisons over at VelocityJS.org. In particular, this article demonstrates how to use Velocity to improve your UI animation workflow. In a concise showdown, eight of Velocity's features are compared against their jQuery counterparts.

If you feel that your current UI workflow is messy, poorly segregated, or too reliant upon jQuery’s broad array of style functions, then this walkthrough is for you.

Brief Overview

Before we dive into Velocity, let's quickly cover the bases: It should be pointed out that both $.animate() and $.velocity() support a malleable options syntax. You can either pass in options as comma-separated values, or you can pass in a standalone options object.

Here's an example of the comma-separated syntax, in which an integer is treated as the animation's duration, a string is treated as the easing type, and a function is treated as a callback (which is triggered upon the animation's completion):

$div.animate(
  { 
    opacity: 1 
  }, 
  1000, 
  "linear", 
  function() { 
    alert("Done animating."); 
  }
);

Next, here's an example of the object syntax:

$div.animate(
  { 
    opacity: 1 
  }, 
  { 
    duration: 1000, 
    easing: "linear", 
    complete: function() { 
      alert("Done animating!") 
    }, 
    queue: "myQueue" 
  }
);

Beyond producing cleaner-looking code, using the options object provides access to additional animation parameters that are otherwise not able to be specified via the comma-separated syntax.

An example of one such option provided by jQuery is "queue". Velocity also provides the queue option, and multiple animation calls chained onto a single element automatically queue onto one another.

Here, a div's opacity will be animated to 1 for 1000ms then back down to 0 for the next 1000ms:

$div
  .animate({ opacity: 1 }, 1000)
  .animate({ opacity: 0 }, 1000);

Now, with the bases out of the way, let's start comparing Velocity to jQuery.

Reversing

In place of a properties map, Velocity also accepts "reverse" as its first parameter. Reverse animates the target element toward its values prior to its previous Velocity call.

In jQuery, that would be like:

$div
  /* Fade an element in while sliding it into view. */
  .animate({ opacity: 1, top: "50%" })
  /* The values below are what we originally set the element to in our stylesheet. Animate back to them. */ 
  .animate({ opacity: 0, top: "-25%" });

In Velocity, it's easier as it is not only less code, but you don't have to repeat values from your stylesheet:

$div
  .velocity({ opacity: 1, top: "50%" })
  .velocity("reverse");

By default, Velocity's reverse command uses the same options that were passed into the previous Velocity call. These options can be extended by passing new options into the "reverse" call. For example:

$div
  .velocity({ opacity: 1, top: "50%" }, 1000)
  /* Animate back to the prior visual state at half the duration of the previous animation. */
  .velocity("reverse", 500);

Scrolling

A popular UI technique is to scroll the browser so that it's aligned with an element further down the page, then to animate that element with attention-grabbing flourishes. Pulling this off with jQuery involves messy, non-performant code:

In jQuery, animating the scrollTop property requires you to target both the html element and the body element in order for the animation to work in older versions of Internet Explorer.

$("html, body").animate(
  { 
    scrollTop: $div.offset().top 
  }, 
  1000, 
  function() {
    /* We use a callback to fade in the div once the browser has completed scrolling. */
    $div.animate({ opacity: 1 });
  }
);

In Velocity, you target the element you want to scroll to:

$div
  .velocity("scroll", 1000)
  .velocity({ opacity: 1 });

Just as with Velocity's "reverse" command, "scroll" can be passed in as Velocity's first parameter in place of a properties map. Also like the reverse command, the scroll command accepts animation options and can be chained onto other calls.

The scroll command's behavior is straightforward: Scroll the browser to the top of the element targeted by the Velocity call.

Looping

Oftentimes, an element's animation needs to be looped. Examples include shaking a dialog box to indicate invalid user input or bouncing a notification icon to grab the user's attention.

In jQuery, looping an animation entails messing your animation logic by breaking part of it out into a for statement:

for (var i = 0; i < 5; i++) {
  $div
    /* Slide the element up by 100px. */
    .animate({ top: -100 })
    /* Then animate back to the original value. */
    .animate({ top: 0 });
}

In Velocity, simply set the loop option to an integer equal to the desired number of loop cycles. A single loop cycle consists of animating toward the values in the property map followed by reversing back to the original values.

$div.velocity(
  { top: -100 }, 
  { loop: 5 }
);

Fading Elements

You'll often find yourself fading in an element whose display property was initially set to none, so that the element wasn't immediately visible upon page load. Subsequently fading in these elements requires several lines of jQuery:

$div
  /* Use jQuery's $.show() function to make the element visible by switching its display property to "block"/"inline" as appropriate. */
  .show()
  /* Set the element's starting opacity to 0 so that it can be gradually faded in by the subsequent animation call. */
  .css("opacity", 0)
  /* Fade in and slide into view. */
  .animate({ 
    opacity: 1, 
    top: "50%" 
  });

In Velocity, you simply pass in display as an option. The display option accepts the same set of values that its CSS property counterpart does (e.g. "block", "inline", and "none").

$div.velocity(
  { 
    opacity: 1, 
    top: "50%" 
  },
  { 
    display: "block" 
  }
);

When the display option is set to a value other than none, the element's display property is set to the provided value at the start of the animation. Conversely, when display is passed a value of none, the display property is set upon the animation's completion.

$div
  /* Fade out and slide out of view. */
  .animate({ opacity: 0, top: "-50%" })
  /* Then set the display property to "none" via a queued $.fadeOut() call. */
  .fadeOut(1);
$div.velocity(
  { 
    opacity: 0,
    top: "-50%" 
  }, 
  { 
    display: "none" 
  }
);

Further, if an element's opacity is being animated to a non-zero value while its display option is being set to a value other than none, Velocity conveniently defaults opacity's start value to 0.

Delaying

Velocity accepts a delay option that replaces having to sprinkle $.delay() calls throughout your animation code:

$div
  .delay(1000)
  .animate({ 
    opacity: 1 
  });
$div.velocity(
  { 
    opacity: 1 
  }, 
  { 
    delay: 1000 
  }
);

Beyond consolidating animation logic into a single call, using Velocity's built-in delay option allows Velocity to optimize chained animations by caching values between them.

Sequences

A feature unique to Velocity is sequences, which are macros for animations: An animation sequence is created once, then it can be subsequently triggered when desired across elements on all your pages.

The benefits of sequences include:

  • Naming your animations for better code organization.
  • Separating UI animation logic from UI interaction logic.
  • Packaging animations for sharing across your projects and with other developers.

Sequences are created by extending the $.Velocity.Sequences object. They are thereafter triggered by passing in the sequence's name as Velocity's first argument.

Below is a simple "hover" sequence:

$.Velocity.Sequences.hover = function (element, options) {
  var duration = options.duration || 750;

  $.Velocity.animate(element,
    { 
      translateY: "-=10px",
    }, { 
      /* Delay is relative to user-adjustable duration. */
      delay: duration * 0.033,
      duration: duration,
      loop: 3,
      easing: "easeInOutSine"
    });
};

Now, you can apply it to an element:

$div.velocity("hover");

In the above sequence, the element translates up then down by 10px three times (loop: 3) with a short intermittent delay.

To learn more about the nuances of sequences, read the documentation of it.

Velocity uses its own sequences feature to pre-package in fadeIn, fadeOut, slideUp, and slideDown functions (which are identical to their jQuery equivalents).

For example, slide a container div down into view:

$div.velocity("slideDown", function() {
  /* Then fade in its children over a duration of 1000ms. */
  $children.velocity("fadeIn", 1000);
});

Forced Hardware Acceleration

Forcing hardware acceleration (HA) on an element is an easy to way to dramatically increase animation performance on mobile devices. Enabling HA is traditionally achieved by setting an element's transform property to translateZ(0).

$div
  .css("transform", "translateZ(0)")
  .animate({ opacity: 1 })
  .css("transform", "none");

In Velocity, HA is automatically applied on mobile devices (there's no performance boost to be gained on the desktop). Velocity's control over HA is highly optimized.

$div.velocity({ opacity: 1 });

Wrapping Up

The purpose of this walkthrough has been to demonstrate Velocity's consolidation of animation logic within your code. In short, Velocity is an expressive and efficient tool for crafting UI animations.

While jQuery is tremendously powerful, it was never jQuery's design goal to function as an optimized animation engine, and it suffers accordingly from less-than-ideal performance and workflows. At just 7Kb zipped, Velocity packs in enough features and speed gains for you to consider making it your animation engine of choice.

To explore the remainder of Velocity's features, including color and transform animation, check out Velocity's documentation at VelocityJS.org.

Before we conclude, here are some extreme examples of web animation that are made possible through the expressiveness and speed of Velocity:

Comments

  1. Awesome stuff. Does this mean we shouldn’t use the transition CSS property anymore?

    • Hey Mike! Fair question. Here’s an excerpt from a comment of mine elsewhere:

      “My recommendation is to use raw CSS transitions when you’re exclusively developing for mobile and your animations consist solely of simple state changes. In such circumstances, transitions are a performant and native solution that allow you to retain all animation logic inside your stylesheets and avoid bloating your page with JavaScript libraries. However, if you’re designing intricate UI flourishes or are developing an app with a stateful UI, always use an animation library so that your animations remain performant and your workflow remains manageable. One library in particular that does a fantastic job at managing CSS transitions is Transit.”

  2. standard-div
    Permalink to comment#

    This is a fantastic, immediately usable, summary. Thanks.

  3. Maxime
    Permalink to comment#

    Better than GSAP?
    I’m not sure.

    • It’s not the point. GSAP is better for e.g. games, and Velocity is for UI. Velocity is simple to use and fully open source (GSAP requires licensing fee). More at http://davidwalsh.name/css-js-animation

    • Julian Shapiro

      +1

    • AsifAmeer

      I agree with Michal GSAP is a suite of tools for scripted, high-performance HTML5 animations, games etc the thing that I really like about GSAP that it’s compatible with all major browsers as I really don’t dig in or use GSAP I am ok with ordinary syntax

  4. Okay, Julian, you’ve peaked my interest. I especially like how Velocity can use CSS animations as a blueprint for the actual JS transformation. Very slick.

    • Thank you so much, Ryan. If you toy around with Velocity and have any questions, I’m always available on Twitter at @Shapiro.

  5. maxisix
    Permalink to comment#

    VelocityJS isn’t built for complex sequencing like GSAP. But it look really good for simple animation :)

    • GSAP is an amazing full-fledged animation suite with a ton of power.

      Velocity’s focus is being a very fast tool for improving UI animation performance and workflow.

  6. Kevin Lozandier
    Permalink to comment#

    I’m confused on why it depends on jQuery in this particular case, it seems $.queue is the cause of that.

    Is the implementation of promises (natively or a via a library such as RSVP) too convoluted or unfeasible to you, Julian?

    Or $.animate ensures a LOT of work is saved on your part from having the plugin be independent of jQuery.

    • Hey Kevin,

      Re. jQuery: We’re currently working on removing jQuery dependence — https://github.com/julianshapiro/velocity/issues/5. It won’t be difficult. I designed Velocity to be minimally reliant on jQuery.

      Re. Promises: That’s a completely reasonable feature addition. Would you be interested in filing a GitHub issue for it?

      Thanks, man :)

    • Gamanuel Fleurmond
      Permalink to comment#

      Promises would make this so powerful

    • Kevin Lozandier

      Hey, Julian:

      I’m only seeing this now; will make an issue ticket by the end of the day (if it hasn’t been made).

      You can technically use JavaScript’s native Promises (ES6) to change jQuery’s to a more proper implementation using Promise.resolve()

      Jake ‘The Great’ Archibald has a great article on HTMl5Rocks about this a while back.

    • Julian Shapiro

      Hey, Kevin! Thanks so much for following up. Yes, please do open an issue.

      I’ll check out the HTML5Rocks article this afternoon :)

  7. Regarding of the looping, here’s the JQuery way :)

    var anim = [
        {width:100,height:30},
        {marginTop:200,marginLeft:100},
        {fontSize:30,padding:40},
        {borderWidth:10},
        {marginTop:0}
    ];
    
    $.each(anim, function(i) {
        $('div').animate(anim[i], 1000);
    });
    

    Demo: http://jsfiddle.net/tovic/KzRcF/1/embedded/js,result,html,css

  8. I think, velocity.js is a better for simple animations, not a advanced like gsap.

  9. Nice tut thx bro :)

  10. Check this library out: http://motorcortexjs.com/
    It’s been built upon velocity.js. With MotorCortex.js you can define all your animations through external CSS-like syntax files and just trigger events through javascript, in order to fire them.
    Full logic – animation/design decoupling.

  11. Lucas
    Permalink to comment#

    I got really frustrated with velocity. Can’t use the reverse with css scale, complete callback somehow confuses everything and keep bouncing the object. And when I tried the UI Pack it keep sending me “First argument was not a property map, a known action, or a registered sequence. Aborting.”, there is no signal for what I need to use, because everywhere he keeps using $elements. So I guessed it should be something like $(‘div’), but it keep sending me the error. With the description and simple actions I recommended velocity, but now, I’m not sure now if you will find any support if needed.

    I waste a lot of time trying to figure out what is happening, but there is no comments and no documentation covering that.

    • Lucas
      Permalink to comment#

      Ignore the above comment please, it was a problem in the javascript order. If you have the same error “First argument was not a property map, a known action, or a registered sequence. Aborting.”, check your script order and if the ui pack is below the velocity.

      Amazing plugin, the only problem that persists is the scale one.

    • Julian Shapiro
      Permalink to comment#

      Hey Lucas!

      I appreciate you voicing your concerns :)

      To be blunt with you: If you’re new to jQuery/JavaScript/programming/web animation and have questions about basic implementation details, you should check out StackOverflow.com.

      If you’ve already gone down that path and believe you’ve encountered an actual bug within Velocity, there is a very active GitHub issues channel where I greatly welcome all bug reports: https://github.com/julianshapiro/velocity/issues?state=open. I have a strong track record of fixing them incredibly quickly :-p

      All you have to do is demonstrate your bug using JSFiddle or CodePen, then open a new issue describing the difference between the behavior you expect to see and the behavior Velocity is actually executing. This applies to any project on GitHub. Come join the conversation :)

      With that out of the way, nothing that you’ve reported in your comment above has been reported by anyone else. (And thousands of developers are using Velocity.)

      Further, the way you’ve described your issues is vague, and it’s therefore difficult to respond with specific help. Despite that, here’s my best stab at addressing your concerns:

      1) Using reverse on scale works fine in all my tests. If you can put together a JS Fiddle example, it would be my pleasure to look into your issue further!
      2) Try your complete callback code using jQuery’s $.animate() instead of $.velocity(). If the error still exists, the issue is with your own code.
      3) For the UI Pack, you either didn’t load the file after Velocity or you’re entering an incorrect effect name.
      4) Not sure what you’re talking about at the end re. $(“div”).
      5) Re. documentation: There is a lot of documentation at VelocityJS.org.

      Again, pardon my bluntness when I assume that you’re a beginning JavaScript programmer. But, when someone’s broadly mistaking bugs in their own code for bugs in Velocity, I need to respond in the affirmative so that readers do not mischaracterize the quality and reliability of Velocity :)

  12. Julian Shapiro
    Permalink to comment#

    Oops. I only just saw your follow-up comment :) Thanks for the kind words. Re. Scale issue: Let’s fix it together. I’m around if you’d like to throw together a code example.

    • Lucas
      Permalink to comment#

      Hi Julian, I’m really happy with the velocity ( ba dum tiss ) that you answered me. I guess I’ve just found my problem. My button have transitions, for hover. When I remove that transitions the scale effect works fine: http://jsfiddle.net/hspNd/

      It also works in my site. So, my question is: Should I use jquery hover instead css animation in this case?

  13. Julian Shapiro
    Permalink to comment#

    Haha :-D

    1) Correct, your transition declarations via CSS will conflict with the Velocity animations.
    2) Good news. There’s an easy fix: Just place all the *-transition CSS styles inside the hover class itself :)

    • Lucas
      Permalink to comment#

      Thank you Julian! Now everything works fine. I’m sorry for not contacting via the right channel, I did it because I was really excited about the velocity and got frustrated, but now I’m right that this will be my must have in the bootstrap for the next projects.

    • Julian Shapiro
      Permalink to comment#

      Wicked. Awesome to hear, Lucas. Don’t be sorry — not a prob. Just check out SO/GitHub when you need help with anything :)

  14. Hey Julian,
    This looks pretty great. In your opinion, how does this differ from Transit. I’m a little confused.

  15. Nick
    Permalink to comment#

    Height/Scroll changes are still a little rough on mobile (Testing an old GS3 – blaming the hardware now) but better than css3 transitions or raw jquery (though, that’s not much of a challange (;). I really like the functionality of this plug in – its perfect for UI – and has an extremely small file-size (seriously, how..)

  16. Kiran
    Permalink to comment#

    Hi Julian,

    I want to stop the animation after it has executed once. How can I do it? I am using your sample code

    setInterval(function() {
      $("div")
        .velocity("transition.slideLeftIn", { stagger: 250 })
        .delay(750)
        .velocity({ opacity: 0 }, 750)
    }, 2000);
    

    Thanks! And appreciate your awesome work! :)

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".