Make Your Website Interactive and Fun with Velocity.js (No jQuery)
Special thanks from me go to James Hibbard and the developers behind Velocity for reviewing this article. Also to users and developers who contribute and have contributed to Velocity over the years.
In this article I introduce Velocity.js, a fast and high-powered JavaScript animation engine by Julian Shapiro. By the time you go through all the demos, you’ll be able to use Velocity.js to create your own animations and make your website more interactive and user-friendly. All of this without using jQuery, just vanilla JavaScript.
This is the third article in the series Beyond CSS: Dynamic DOM Animation Libraries.
Here’s what I have already covered:
- Animating the DOM with Anime.js touches on how best to use animation on the web and when you could consider using a JavaScript animation library instead of CSS-only animation. It then focuses on Anime.js, a free and lightweight JavaScript animation library
- Fun Animation Effects with KUTE.js introduces you to KUTE.js, a free and feature-rich JavaScript animation library.
What You Can Animate with Velocity.js
Velocity.js is a powerful library, which puts the DOM at your fingertips! It lets you animate:
- Numeric values of CSS animatable properties, including colors
- Transforms
- SVG properties
- Scroll events, both relative to the page or to a container element inside the page
- Fade and slide animations.
In general, Velocity animates one numeric property value at a time. For instance, if you want to translate an element along both X and Y coordinates, you can’t use something like translate['10px', '15px']
. Rather, you should accompany the translate property with its corresponding axis, like this: translateX: '10px', translateY: '15px'
. There is one feature called forcefeeding, which Velocity makes available to let you specify two values at the same time. I’m going to introduce forcefeeding later in this article.
Options
Velocity’s options object gives you quite a bit of flexibility in crafting your animations.
Here’s a list of the options you’ll see in the demos for this article:
- Duration: how long each animation lasts. The unit of measurement for duration is milliseconds
- Easing: Velocity supports most jQuery UI easing types, CSS3 easings, i.e., “ease”, “ease-in”, “ease-out”, and “ease-in-out”, bezier curves, step easing, and even cool spring physics. You can play with this demo to see the spring physics option in action
-
Loop: how many times the animation should be repeated. If you set this option to
true
, it will run indefinitely - Delay: how long to wait before the start of an animation.
A full list of options, is available on Velocity’s docs page.
Syntax
If you’re a jQuery user, Velocity.js makes things easy for you. In fact, Velocity has the same API as jQuery. To get started:
Download Velocity, include it on your page, and replace all instances of jQuery’s
$.animate()
with$.velocity()
.
However, you don’t need jQuery to work with Velocity, and you are not going to use jQuery for the demos in this article. The syntax will be a bit different from what you would use if jQuery were included. Here’s what it looks like:
Velocity(element, {property: value}, {option: optionValue});
To chain another animation on the same element, just add another Velocity call after the previous one:
Velocity(element1, {property: value}, {option: optionValue});
Velocity(element1, {property: value}, {option: optionValue});
To apply an animation to multiple elements at the same time, just cache all of the elements into a variable and call Velocity on that variable, no need to write your own loop. For instance:
const elements = document.querySelectorAll('<div>');
Velocity(elements, {property: value}, {option: optionValue});
You can use px
, %
, rem
, em
, vw/vh
and deg
. If you don’t add a unit, Velocity assumes an appropriate unit for you, usually px
.
Velocity also supports operations with +, –, * and /, as well as relative math operations by adding an equal (=) sign after each operator, e.g., '+=3em'
Velocity.js Forcefeeding: Passing Initial Values
Instead of letting Velocity.js query the DOM to get an element’s initial value, you can set it yourself using this syntax:
Velocity(element, {
translateX: [endValue, startValue],
backgroundColor: [endValue, easing, startValue]
}, {
//options here
});
In this case, you pass an array of two, optionally three, items:
- The first item is a value for the final state of your animation
- The second, optional, item is an easing option applied to that specific property
- The starting state of your tween, that is, the values you explicitly set for that specific property at the beginning of the animation, is the the last item in the array.
You can read more on forcefeeding on Velocity’s docs.
Taking Control of Velocity.js Animations
You can stop, pause, reverse and resume all Velocity calls on an element using this syntax:
- To stop:
Velocity(elem, 'stop');
- To pause:
Velocity(elem, 'pause');
- To reverse:
Velocity(elem, 'reverse');
- To resume:
Velocity(elem, 'resume');
Armed with these basic instructions, you can start diving into some practical examples.
Demo: Falling Ball
Start with a simple ball falling from the top of the page.
const ball = document.querySelector('.ball');
Velocity(ball, {
translateY: '130px'
}, {
easing: [1000, 20],
duration: 2000
});
The code above selects an HTML element with the class of .ball
, translates it 130px along the Y axis over 2 seconds (just for demonstration purposes, otherwise I recommend a much shorter duration) with a movement that accelerates as it falls and gets bouncy at the end.
You can quickly achieve this with Velocity spring physics as an array value for the easing option: the first array item represents tension, the second one represents friction. A high tension value increases total speed and bounciness (default is 500), a lower friction value increases the vibration speed at the end (default is 20).
For the fun of it, have the ball’s background color animate from an initial value of a bluish color to a dark color. To set the initial value for the background color, you need to use Velocity.js forcefeed:
Velocity(ball, {
translateY: '130px',
//array items: endValue, startValue
backgroundColor : ['#222', '#043d99']
}, {
//options here
});
And that’s it for this basic implementation of Velocity.js. Have a play with the code below:
See the Pen Simple falling ball with Velocity.js by SitePoint (@SitePoint) on CodePen.
Demo: Button-Controlled Bouncing Ball
For the next demo, the goal is to create this animation sequence:
- The ball falls from the top
- It looks a bit squashed as it hits the ground
- It gains its natural shape as it bounces back up
- This animation keeps going in a loop
- You can stop and restart the looping animation at the click of a button.
Achieving this kind of animation requires stringing together a number of tweens and controlling their animation as a whole using buttons.
The ideal tool for this would be a timeline which would encompass all the tweens and make it possible to control when all of the tweens start and end. Velocity.js does not have a native timeline, but you have a couple of options:
- Using Tweene — this is an animation proxy, that is, a wrapper you can use with a number of JavaScript animation libraries, including Velocity.js. I’ve tried this route, but unfortunately, Tweene expects Velocity to work with jQuery, which is not the case here. Perhaps you can tweak Tweene’s code, but this is not ideal
- Resorting to JavaScript
requestAnimationFrame()
, which at the time of writing is supported in all major browsers except Opera Mini. This is a native API for running any kind of smooth, performant animation in the browser environment, e.g., CSS, canvas, etc., and it’s the approach you’ll be using here every time you need this kind of functionality.
Splitting Tweens into Different Functions
To keep the code clean, you could build a function for the animation scenes you need. Then, you would just call these functions inside what I call a master function, which contains the requestAnimationFrame()
method.
Here’s the code:
const changeBallPosition = (elem, propVal, easingVal, durationVal) => {
Velocity(elem, {
translateY: propVal
}, {
easing: easingVal,
duration: durationVal
});
};
const changeBallWidth = (elem, propVal, easingVal, durationVal) => {
Velocity(elem, {
scaleX: propVal
}, {
easing: easingVal,
duration: durationVal
});
};
The snippet above contains examples of how to write ES6 arrow functions. You need to get rid of the keyword function
and use a fat arrow symbol(=>
) after parentheses instead.
The function is stored in a constant using the const
keyword. Without diving too deep, let’s say that you cannot update the value of constants. If you need to store a value that needs updating throughout your program, use let
instead. To learn more, ES6 let VS const variables by Wes Bos is a great read.
As you can see, each function contains a Velocity call that causes the ball to perform a specific movement. Notice that to move the ball and change its width, the code doesn’t change CSS top
and width
property values respectively. Rather, it changes the values of the translate
and scale
properties, which bring about a much more performant animation.
Here’s the master function with the timer. It’s here that you place a call to the functions above:
let animationFrameID;
const launchBall = (elem) => {
changeBallPosition(elem, '130px', 'easeInQuart', 300);
changeBallWidth(elem, 1.2, 'linear', 50);
changeBallWidth(elem, 1, 'linear', 50);
changeBallPosition(elem, '-10px', 'easeOutQuart', 300);
changeBallWidth(elem, 1, 'linear', 50);
animationFrameID = requestAnimationFrame(
() => {
launchBall(elem);
});
};
Notice the global animationFrameID
variable. You will need this variable to stop the animation with cancelAnimationFrame()
later in the code, so hold on to it!
To set the ball in motion, handle the Play button’s click event by calling the launchBall()
function and passing the ball
argument to it:
btnPlay.addEventListener('click', function() {
launchBall(ball);
this.disabled = true;
btnStop.disabled = false;
});
Notice how this time you use the function
keyword to write the callback that handles the click event. This is so because you are using the this
keyword to refer to the button that is being clicked i.e., this.disabled = true;
. If you used an arrow function, the this
keyword would refer to the global window
object, which would cause an error and prevent you from achieving the desired result. In short, don’t use arrow functions in callback functions with dynamic context.
Once the animation is triggered, you don’t need users to keep clicking on the Play button, so the next line of code disables it while also enabling the Stop button, so users can stop the animation at any time.
To stop the ball, you need a new function:
const removeAnimFrame = () => {
if (animationFrameID) {
cancelAnimationFrame(animationFrameID);
}
}
Here, you place the call to cancelAnimationFrame()
by passing animationFrameID
, which as you remember, contains a reference to the ball’s looping animation.
Finally, this is how you would handle the Stop button’s click event:
btnStop.addEventListener('click', function() {
removeAnimFrame();
Velocity(ball, 'stop', true);
this.disabled = true;
btnPlay.disabled = false;
});
This code:
- Removes the looping animation
- Calls
Velocity(ball, 'stop', true);
to stop the animation - Disables the Play button
- And restores the Stop button’s functionality.
The interesting bit of code is the call to Velocity.js stop()
method with an additional boolean (true or false) argument. This is necessary to clear the animation queue. If you leave this argument out and click the Stop button, the ball won’t immediately stop animating. It will stop animating only once all the queued Velocity calls have finished executing (see Clearing the Animation Queue, inside the Stop section in the Velocity.js docs).
Have a peek at the demo to review the entire code:
See the Pen Controlled bouncing ball with Velocity JS by SitePoint (@SitePoint) on CodePen.
Scrolling Animation
With Velocity.js you can quickly implement both vertical and horizontal scrolling animation. Scrolling can be in relation to the entire page or a containing element. Either way, you always call Velocity on the element you’re scrolling into view.
The demo below uses two links: clicking the top link scrolls the container to the last section, clicking the bottom link scrolls the container to the first section.
Since the scrolling action is the same for both links, to avoid repeating the same code twice, organize it into a function. Here’s what it looks like:
const scrolling = (element, container, direction) => {
let offsetDistance = 0;
direction === 'up' ? offsetDistance = -200 : 200;
//velocity call
Velocity(element, 'scroll', {
container: container,
duration: 500,
offset: offsetDistance,
easing: 'ease-out'
});
};
-
The
element
parameter stands for the element that you want to scroll into view, in this case either the first or the last section, depending on the direction of the scroll -
The direction is stored in the
direction
parameter and its functionality is determined by how the ternary operator works. In particular: if the value ofdirection
is ‘up’ (direction === 'up' ?
), then the value ofoffsetDistance
is -200px, which moves the page 200px above the element being scrolled into view (offsetDistance = -200
), otherwise the value ofoffsetDistance
will be 200px (: 200
), which offsets the page 200px below the element being scrolled into view. TheoffsetDistance
parameter will store a value for Velocity’soffset
option property, which lets you offset the target scroll position by a specified amount in pixels -
Because the scrolling in the demo is not relative to the browser window but to a containing element, the Velocity call needs that information, which in the code above is stored in the container parameter. Also because of this, set the CSS
position
property of the containing element to eitherrelative
,absolute
, orfixed
;static
doesn’t work.
Finally, you handle the click event on the relevant links by calling the function above. For instance, to scroll to the last section, your event handler could look something like this:
Link.addEventListener('click', (e) => {
e.preventDefault();
scrolling(lastSection, scrollerContainer, 'down');
});
Here’s the full code:
See the Pen Page scrolling with Velocity.js by SitePoint (@SitePoint) on CodePen.
SVG Animation
Velocity can animate any property with a single number value, including CSS properties applied to SVGs and SVG-specific properties, e.g., fill
, stroke
, stroke-width
, stroke-color
, rx
, ry
, etc.
For a full list of SVG properties Velocity.js can animate, have a look at the Velocity docs on SVG animation.
The demo below shows an SVG image of a smiling fish. Bubbles fade in and out of view and its eye blinks every few seconds. If you click the Play button, the fish moves to the left of its container, disappears, returns and turns around.
Bug alert: unfortunately, IE/Edge browsers have no support for CSS transforms and Velocity does not provide a compatibility fix for this bug. Therefore, the demo doesn’t work as expected in those browsers.
Get Your SVG Image Ready for Animation
Before writing any code, make sure your SVG image is ready to be animated using Velocity.js.
- Add class or ID attributes to the parts of the SVG you plan on animating. This will make it easy for you to target those parts in JavaScript
- If you want to animate some elements as a whole, wrap thos elements inside
<g></g>
tags and slap a class attribute or ID attribute for easy manipulation in your JavaScript code - Simplify and optimize your graphics.
The JavaScript Code with Velocity.js
Once again, package most of your code into functions, for more flexibility and less repetition.
As an example, here’s the function that moves the fish:
const moveFish = (elem, moveBy, initialPos, btn, bool = false) => {
Velocity(elem, {
translateX: [moveBy, initialPos]
}, {
duration: 5000,
easing: 'linear',
complete: () => {
if(bool) {
btn.disabled = false;
}
}
});
};
The syntax for SVG animation is not different from animating HTML elements. Here’s what the code above does in more detail:
- The code makes a Velocity call on an element and uses forcefeeding to set the value for the
translateX
property, which determines both final and initial positions for the element. When you later call this function the argument you will supply for the element parameter will be a reference to the SVG fish - It takes advantage of Velocity.js built-in complete() method to activate the Play button only after the entire animation ends. This is to prevent users from repeatedly pressing the button during the course of the animation, which would build the animation queue
- After the animation is finished and the Play button is active again, users can choose to replay the animation, if they so wish. This functionality works via the
bool
parameter. If the value ofbool
is true when themoveFish()
function is called, the native Velocity.js complete() method insidemoveFish()
fires at the end of the animation and reactivates the button - Finally, notice another ES6-specific feature, default parameters. You set a default value, in this case is
bool = false
, and when you callmoveFish()
you can choose to leave out the corresponding argument because what you set as your default will be automatically applied. Alternatively, you can change the default by explicitly entering an argument. To see this in action, pay attention to the next bit of code, which contains a call to the function above.
To achieve different moving animations, call moveFish()
a number of times using different arguments inside a master function, like this:
const play = () => {
moveFish(fish, '-1000', 0, btnPlay);
moveFish(fish, 0, '-1000', btnPlay, true);
//more functions here
};
Take note of the different ways in which you call moveFish()
: the first time without the fifth argument and the second time with the fifth argument with a value of true
. In the first case, the value for the fifth argument is the default parameter you supplied when you wrote the moveFish()
function.
Finally, just call the play()
function on the Play button’s click event:
btnPlay.addEventListener('click', function() {
this.disabled = true;
play();
});
To see all the pieces of the animation at work, have fun experimenting with the demo below.
See the Pen SVG Animation with Velocity.js by SitePoint (@SitePoint) on CodePen.
Velocity UI Pack
You can complement Velocity.js with Velocity UI Pack, a plugin that greatly improves your animation workflow.
You need to download the UI pack and reference it below the main Velocity.js library.
This plugin gives access to cool pre-registered effects like bounceIn/Out, swirlIn/Out, fadeIn/Out, etc. You can see the list of all effects you can get out of the box in the UI Pack docs. On top of this, you can also register your own custom effects.
In the demo below, I use Velocity.js UI Pack to hide a form after submission and show a success icon to the user.
Here’s what the Velocity call to hide the form looks like (inside the hideForm()
function):
Velocity(formEl,'transition.bounceUpOut', 500);
- The first argument is the element you are animating, i.e., the form in this case
- The second argument is one of the UI Pack’s pre-registered effects, i.e., bounceUpOut (the effects are divided into transitions and callouts and you prefix the effect with the appropriate category)
- The last one is the duration of the animation.
Have a look at the demo below for all the details:
See the Pen Animated sign up form with Velocity.js UI Pack by SitePoint (@SitePoint) on CodePen.
More Resources
These are some links to resources around the web, where you can learn more on Velocity.js:
- Incredibly Fast UI Animation Using Velocity.js
- Faster UI Animations With Velocity.js
- Improving UI Animation Workflow with Velocity.js
- Velocity.js: The Official Collection (CodePen)
Conclusion
In this article I have introduced Velocity.js and showed how you can work with it without the jQuery dependency.
I have found the library’s syntax intuitive and user-friendly, even more so for those who are familiar with the jQuery library. Documentation is thorough and offers tons of demos to illustrate each feature.
Below are just a few considerations, which relate to the use of Velocity.js without jQuery and to SVG animation:
-
The Velocity.js UI Pack exposes a function called
$.Velocity.RunSequence()
, which combines multiple Velocity calls into a a single effect you can then reference by name. This feature would have been super handy when dealing with more complex animation sequences. Unfortunately, I didn’t manage to make it work without jQuery - Such a powerful library would have benefited from making available a timeline. Using Tweene could have been a solution, but again, integration between Tweene and Velocity without jQuery is not straightforward
- Not offering a fix for IE/Edge browsers’ lack of support for CSS transforms is a limiting factor for me when using Velocity with SVG.
It’s highly likely the points above will be addressed in the future by the developers behind the project. In the meantime, remember that Velocity.js is open-source. Consequently, if you can think of any enhancements or find a bug, you have the option of sending a pull request or leaving a comment in the issues section of the Velocity.js repo on GitHub.
Have you used Velocity.js for your animation projects? What has your experience been like? Do you have any animations you’d like to share? Use the comment box below to let us know.
Credits: for the SVG demo, the graphic is an adapted version of the Goldfish from Pixabay, the featured image is courtesy of Unsplash, and the woman photographer image in the last demo is courtesy of Gratisography