Explore the new frontier of animation with CSS

A flat illustration of spaceships, planets, satellites and comets, indicating the new frontier of CSS animation.

Modern browsers and design tools offer a lot in terms of creative power. Mobile devices have turned into pocket powerhouses with enough oomph to push all those Retina screen pixels without breaking a sweat. It should therefore come as no surprise that dynamic websites, which tap into all this power, are emerging on a daily basis. In fact, you would be hard-pressed to find a modern website that doesn’t make use of CSS animation in some way, be it in the form of simple hover transitions or in full-blown pieces of art.

Good animation can bring otherwise static content to life while supporting the rest of the design and helping to express brand personality, and it can make for a more natural user experience because we're hardwired to respond to moving objects.

Why use CSS for animation?

Compared to script-driven animations, animations using CSS are easier to learn and can be used without having to know JavaScript. They can be made responsive as they can be modified through CSS media queries. Despite having a relatively simple syntax, we can create quite complex animations with it, especially with the help of CSS preprocessors.

Using CSS for animation consists of a style describing the animation and a @keyframes block that defines intermediate steps in an animation sequence. All aspects of the animation are controlled via a set of easily understandable properties: animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode and animation-play-state. There is also the animation property, a shorthand syntax that combines all of the others.

This is what the CSS animation code looks like in its simplest form:

/* Animation description */
.slide-right {
animation: slide-right 0.5s ease-in-out 0.2s infinite alternate both;
}
/* Animation steps */
@keyframes slide-right {
  0% { transform: translateX(0); }
  100% { transform: translateX(100px); }
}

Using the same syntax, it is possible to animate SVG the same way as any other HTML element.

We will explore various aspects of CSS animation and how we can use it to enhance the overall user experience.

Functional animation

Animations can be applied to perform various functions in the interface. They can successfully guide users through a certain process, improve orientation and also provide visual feedback. Such animations play an extremely important role in designing a high-quality, brand-based user experience. Let’s look at some examples of functional animation.

Page transitions

Clicking the website navigation links usually results in a sudden change in user interface. A page is requested, and when the browser receives a response from the server, a blank screen will flash briefly before the new page is shown. This interrupts the user’s workflow and can be disorienting. Page transitions help minimise the distracting effect.

Instead of letting the browser handle this for us, we can intercept the request, load the new content asynchronously in the background, and then use CSS animation to create a smooth transition to another page when it is ready. This helps to promote a sense of continuity while keeping the context.

Loaders and progress bars

An important aspect of good interaction design is providing visual feedback. We should never leave users wondering what is happening or whether the result of an interaction has been successful or not.

When using page transitions, for example, we should let the user know not only that the page is being loaded but also that it will be displayed shortly. One way to achieve this would be to show an animated loader indicating that the operation is underway.

If it is possible to measure the duration, we could instead show a progress bar. This method provides useful information about how long it will take for the page to load completely.

Beyond loaders – skeleton screens

The alternative solution to loaders are skeleton screens, which can greatly improve perceived performance. A skeleton screen is a simplified graphic representation of the UI to be displayed while the content is loading in the background. The UI is divided into smaller blocks of skeleton images, which are then swapped with real content as soon as it is ready. We can use CSS animation to indicate that the content is loading as well as to ensure that the change appears gradually.

Micro-interactions

Micro-interactions are small tasks we perform almost automatically. Liking a tweet, adding an item to the shopping cart, sharing links – these are all micro-interactions. We can use CSS animation to provide visual cues and make the result of an action easily understandable. One example is making CTAs or various UI buttons appear tangible.

We can also use CSS animation to create a meaningful transition between states, for example, morphing a menu button from its original shape to an ‘X’ icon, hinting that the navigation can be closed by clicking the same button again. Such design is both pleasing as well as being informative.

Animation can also be used to direct users’ attention by highlighting the changes in the UI, like adding a new item to the shopping cart.

Achieving 60fps

One thing to keep in mind when it comes to CSS animation is performance. It is important to keep the animations jank-free and run them as smoothly as possible. Otherwise instead of enhancing the entire experience, you very quickly risk ruining it. While there are no magical recipes for creating smooth animations besides testing frequently, there are a few principles you can follow to minimise the risk.

Hardware acceleration

Always aim to animate only hardware accelerated CSS properties. This should be easy to remember as there are only two: transform and  opacity. The goal is for all changes to happen in the compositing layer, which is the cheapest from the browser's perspective.

Other properties when changed trigger either layout or repaint operations, which are more expensive. Avoid animating them if possible.

Transform properties can be used to scale, skew, rotate and move objects around. Using left, top, right and bottom properties to change an element's position is a common mistake. Animating these will cause the browser to recalculate the layout. Use transform: translateX() and transform: translateY() instead.

Choreograph your CSS

Don’t animate too many elements all at once or you may end up with a slideshow instead of the animation. If you find yourself in a position where you need to animate lots of objects, coordinate their motion. Plan in advance what elements you will animate and how and when you will animate them. 

Animation delays are super-useful in that regard. Well timed, they can also be used to create a neat staggered motion effect. Offsetting animation start times decreases the strain on the browser, as animations won’t be starting at the same time. This is much easier with the help of CSS preprocessors or JavaScript, as they support loop functions.

Here is how to stagger an animation-delay property in SCSS:

.staggered { animation: slide .7s ease-out 
both; }
@for $i from 1 through 10 {
  .staggered:nth-child(#{$i}) {
    animation-delay: 0.05s * $i;
  }
}

It may take a bit of experimenting in order to fully master the choreography but the effort will be rewarded with better performance.

Debugging

Debugging CSS animation can be a daunting task, and having some help in that regard is essential. Both Chrome and Firefox developer tools enable you to see and tweak your keyframe animations, and slow them down, as well as track their performance. It is definitely worth getting familiar with these tools. 

Control CSS animation with JavaScript

Sometimes you need more control over your animation, and this is where JavaScript comes in. There are some things that simply cannot be done in CSS alone. JS enables you to tap into different animation callback functions like animationstart, animationiteration and animationend.

Restarting animation

Although it sounds trivial, restarting the CSS animation on user input is at times surprisingly tricky. Simply removing the animation class from the element and re-adding it doesn't work. You need an extra step in-between and to trigger a reflow on the element. Here is how to do it:

const elem = document.querySelector('#animated-element');
const btnRestart = document.
querySelector('#btn-restart');
const restartAnimation = event => {
  event.preventDefault();
  elem.classList.remove('animating');
  // This triggers reflow
  void element.offsetWidth;
  elem.classList.add('animating');
};
btnRestart.addEventListener('click', restartAnimation, false);

As a last resort, removing the element from the DOM and adding it again will restart the animation as well.

Controlling play state

You can pause and resume the CSS animation with JS in a similar fashion:

const elem = document.
querySelector('#animated-element');
const btnPlay = document.
querySelector('#btn-play');
const btnPause = document.
querySelector('#btn-pause');
const playAnimation = event => {
  event.preventDefault();
  elem.style.animationPlayState = 
'running';
};
const pauseAnimation = event => {
  event.preventDefault();
  elem.style.animationPlayState = 'paused';
};
btnPlay.addEventListener('click', 
playAnimation, false);
btnPause.addEventListener('click', 
pauseAnimation, false);

A look into the future

There are a few exciting standard CSS features outlined in the spec that are currently in the pipeline and partially implemented in some browsers already. Two of them are particularly interesting when looking from the CSS animation perspective: CSS Variables or more accurate CSS custom properties and the Motion Path module.

Animate with CSS custom properties

Although variables have been available in CSS pre-processors for some time now, one thing makes CSS custom properties far more flexible and extremely usable in animation scenarios.

You can certainly take advantage of the fact that you are able to manipulate them dynamically at run-time via the getProperty(), setPropertyValue() and removeProperty() JS methods.For example, your CSS code might look something like this:

#animated-obj {
  --xPos: 100px;
  animation: slide .4s ease-out both;
}
@keyframes slide {
to% { transform: translateX(var(--xPos)); }
}

You can then access the --xPos property in JS:

const elem = document.
getElementById('animated-obj');
// Read the property value declared in our CSS 
code
const currentX = elem.style.
getPropertyValue('--xPos');

Set it to new value

elem.style.setProperty('--xPos', '300px');

Remove the property

elem.style.removeProperty('--xPos');

This opens up interesting possibilities, and provides developers with new ways to pair CSS Variables with animation that weren't possible before. You can see great examples of animating with CSS Variables on CodePen in this feature's images.

It is worth mentioning that custom properties are inheritable. Changing their values will trigger style recalculation for all of their children, so good practice is to set them at the most specific level.

CSS Motion Path module

Motion Path module enables you to animate objects along a custom path. The specification defines the following properties: offset-path, offset-distance and offset-rotate. offset-path defines coordinates on which the object will move during animation, offset-distance specifies a position along an offset-path and offset-rotate defines the direction of the element while positioning along the offset path.

Here is the simplified example in CSS:

.animated-obj {
  offset-path: path('M100,250 C 100,50 400,50 400,250');
  offset-rotate: auto;
  animation: move .5s linear infinite;
}
@keyframes move {
  from { offset-distance: 0%; }
  to { offset-distance: 100%; }
}

Get animating

The days of designing for static screens are long gone, as are the days when animation meant Flash banners and popups. We should welcome the interactive nature of modern web and start thinking about animation in early stages rather than as an afterthought.

If you haven’t already done so, now is the perfect time to dive into the exciting world of CSS animation. With a bit of creativity, careful planning and modern tooling, there is almost nothing that can’t be achieved.

Web design event generate London returns on 19-21 September 2018, offering a packed schedule of industry-leading speakers, a full day of workshops and valuable networking opportunities – don’t miss it. Get your generate ticket now.

Related articles:

Thank you for reading 5 articles this month* Join now for unlimited access

Enjoy your first month for just £1 / $1 / €1

*Read 5 free articles per month without a subscription

Join now for unlimited access

Try first month for just £1 / $1 / €1

Sergej Skrjanec is one half of freelance creative couple C2, alongside Ana Travas. They are designers, coders, tinkerers, judges at CSS Design Awards and makers of Animista.