From Development

How to make CSS Animations

Animations on the internet are not new. They have been used to achieve many goals, including making something more interesting to watch or even more appealing. Sometimes that is what makes a website stand out among the competition! Animations can make UI elements resemble the real world, making them smoothly change while giving the feeling of continuity, action and progress, instead of changing in a blink of an eye.

Even when applied to small elements, animations can help the user remember whether an action was executed or not. In fact, the user is more likely to remember what he/she just did after perceiving something changing little by little, instead of all at once. A simple animation for a loading screen tells more than just waiting with a white page. It’s the difference between knowing something is still happening and wondering if the page is broken.

What are CSS animations?

There are a lot of different ways of achieving an animation on a webpage. You can use a premade animation from a .gif file and use it as a regular image, which can be simple but will make you lose the ability to change that animation within the code. Manipulate HTML elements using JavaScript is a thing that can be done as well, however, it is often a little too expensive in terms of computation. Also, feel free to use CSS and define multiple styles of an element to smoothly change throughout time. It will not only be easier but also allow the browser to optimize performance and efficiency.

CSS offers two different types of animations. The first one is the transition property, which is frequently used for hover effects and other user interactions. The second one is the animation property, which allows creating more continuous animations or, as we will see later, animations with more stages. Check the example of these two properties' effects on the codepen below (if you don't know what codepen is, check our article about this great tool for sharing code snippets):

  • at the left an hover effect using the transition property;
  • at the right an loading effect using the animation property.

See the Pen types of animations by Patrícia Silva (@patsilva_tese) on CodePen.

Key elements of animations

To make simple or more complex CSS animations, it's necessary to master two key elements: Animation Timing and Inner Components. An animation without time associated is the same as having no animation, as it will merely change instantly. Using inner components will make life easier as it is much more likely to need more than one element to enhance animations. Let's check them:

Animation Timing

To create a smooth animation or transition, it's essential to define time limits. On both transition and animation properties, we have duration, that says how much time it takes to go from start to finish, which is defined by the first time unit (seconds or milliseconds). Then, the delay, which determines how much time the element will wait before the animation starts, being defined by the second time unit.

transition:  all   0.5s   linear   0s;

animation:  rotate   1s  linear  infinite   0.1s;

Below, there are four examples that show the multiple effects that different values can create: two hover effects (one with a duration of 0sec and another 0.5sec), together with two loading effects (one with a delay of 0sec and another with 0.1sec, 0.2sec, and 0.3sec for each of the squares).

See the Pen animation timing by Patrícia Silva (@patsilva_tese) on CodePen.

Inner Components

The second key factor and the secret for making more sophisticated animations is the use of inner components. If only one or two extra elements are needed, the :before and :after components can be used, just like in the sample below.

//HTML structure
<div class="my_text"></div>

/* CSS styling */
my_text { ... }
my_text:before {
    content : " " ;
... }
my_text:after {
    content : " " ;
... }

They can be styled as usual on your CSS file, but it won’t be necessary to define them on the HTML. It will automatically associate the extra elements with the main component, leaving the HTML intact. The only difference in the CSS is that you need to define the property content represented by a string. As an example, it’s like describing the text inside a div on the HTML. From the hover effect example, check below how the a:before component was styled and an empty string was used on the content property to only create that little corner.

a {
   color: #FCD63F;
   font-size: 35px;
   text-decoration: none;
   text-transform: uppercase;
   padding: 5px 10px;
   margin: 0px 10px;
   position: relative;
   transition: all .5s
}
a:before {
   content: "";
   position: absolute;
   bottom: -8px;
   left: -8px;
   width: 12px;
   height: 12px;
   border: 3px solid #FCD63F;
   border-width: 0 0 3px 3px;
   opacity: 1;
   transition: all 0.3s
}

In case the animation needs more than two extra elements,standard HTML components can be used. Change the HTML structure and incorporate unstyled components like spans, apply styling, and then apply the transition or animation. The use of multiple components is also useful if you have different types of movements once each component can only take one animation or transition at a time. The example below shows the loading effect: there is a div named container with four spans inside, and the container has one animation which makes it get bigger. Finaly, each span has an animation that makes them rotate.

//HTML structure
<div class="container">
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>

/* CSS styling */
.container {
    width: 90px;
    height: 90px;
    position: relative;
    animation: animate 1s linear infinite;
    transform: rotate(45deg);
}

.container span {
    position: absolute;
    width: 45px;
    height: 45px;
    animation: rotate 1s linear infinite;
}

CSS transitions

So, how is a transition implemented? The first thing to do is define an initial and final style/state of the elements involved, including the :before and :after components. Then, using the transition property, it will inform those components how they will behave between the two states. This transition property is the composition of four other properties: transition-delay and transition-duration (which are time-related properties and we have already covered), transition-property and transition-timing-function.

See the Pen transition property by Patrícia Silva (@patsilva_tese) on CodePen.

Let's check what these last two properties are and how do they work:

transition-property

This part of the transition allows to specify which properties are going to be affected. It can be set to “all”, so all properties that change from one style to another are selected. But it can also be a specific property or a set of them. This is very useful when setting different timings or behaviors between the element's different properties. For example, if you want the background-color to change much faster than the text color, you would use:

transition: color 0.5s linear 0.5s, background-color 0.1s linear 0.5s;  

// instead of 

transition: all 0.5s linear 0.5s;

transition-timing-function

The timing function defines the transition's velocity and has a set of possible values:

  • linear, the velocity will be constant;
  • ease-in, it will start slow and then get faster;
  • ease-out, it will start fast and then get slower;
  • ease-in-out, a mix of the last two: it will start slow, then get faster and slower again;
  • ease, is a variation of the previous one and the default value of this property.

Explore how these different values can affect an animation in the example below. Notice that the transition can keep track of itself. Moving the mouse quickly in and out of the animated component, the animation will not go all the way till the end: it will rollback.

See the Pen transition-timing-function possible values by Patrícia Silva (@patsilva_tese) on CodePen.

CSS animations and keyframes

In contrast to the transition property, there's no need to specify the element properties affected, nor even define an initial and last state on animation one. The animation property gives more freedom due to keyframes usage. Keyframes determine the different styling/states of the component, having a name that will be later used on the animation property. Having just two states, it can be used “from” and “to” to define the initial and final ones. But, in case of wanting more, it can be used percentages and specify something like the rotate animation on the loading effect.

@keyframes rotate {
   0% {transform: rotate(0deg);}
   10% {transform: rotate(0deg);}
   50% {transform: rotate(90deg);}
   90% {transform: rotate(90deg);}
   100% {transform: rotate(90deg);}
}
span {
   position: absolute;
   width: 45px;
   height: 45px;
   animation: rotate 1s linear infinite;
}

Just like the transition property, the animation one is also the composition of other properties. They are: animation-duration, animation-delay and animation-timing-function, that work in the same way as the transition ones; animation-name, where the name of the keyframe appears; animation-iteration-count, to determine how many times the animation will run, which can be a specific number of “infinite”; animation-direction and animation-fill-mode.

animation-direction

This property tells in which direction the animation must render on the keyframe selected, allowing to choose one of the following values:

  • normal, the animation goes from 0% to 100% (default value);
  • reverse, the animation goes from 100% to 0%;
  • alternate, the animation goes from 0% to 100% and 0% again;
  • alternate-reverse, the animation goes from 100% to 0% and 100% again.

See the Pen animation-direction by Patrícia Silva (@patsilva_tese) on CodePen.

animation-fill-mode

Wondering what happens to the component after the animation finish? The animation-fill-mode property has the answer for it. This value tells how the component may behave outside the animation time, in other words, before and after the animation:

  • none, the component is set to its default style;
  • forwards, after the animation is complete, the component will remain as the animation left it;
  • backwards, before the animation starts, on delay time, the component will immediately take the style defined at the start of the animation.
  • both, before and after the animation, the component takes the style the animation defines.

Check the result of each value below. Just click on any of the boxes where the animation has one second of delay and the differences will be clear.

See the Pen JjKbdeE by Patrícia Silva (@patsilva_tese) on CodePen.

What CSS properties can be animated?

Both types of animations element properties can almost be changed, as long as they are represented by unit values. For instance, you’ll be able to see a smooth transition on colors, height and width values, margins and paddings, opacities, transform, etc. However, you won’t see that effect on borders style, position, float, background-img, font-family, etc.

Even though unit/numeric properties can be changed smoothly, not all of them impact the rendering process the same way; some can be slightly heavier than others. When a browser initiates a web page, it will go through some steps: the first is Layout, the second is Paint, and finally, the Composite. If we choose to animate a property that triggers Layout, like width, the browser will repeat the paint and composite. For that reason, the use of properties that only activate the composite step, like transform and opacity should be prioritize. You can check the full list of CSS properties and their triggers.

Transform property

As mentioned before, the transform property is one of the cheapest to animate. However, this does not mean it’s a limited property. In fact, it allows to do a lot of this to the element, including:

  • translate ( x , y ) - Move an element x pixels horizontally and y pixels vertically. Negative values will move left or up and positive ones will move right or down.
  • rotate( y ) - Rotate an element y degrees. Positive values for clockwise and negative for counter-clockwise movement. The effect will happen over the center of the element by default, change it with the transform-origin property.
  • scale( x , y ) - Alter the size of the element. Given two values, x and y, it will change the width of the element x times and the height y times. Given only one value, like w, it will change both width and height w times, keeping the initial proportion of the element. It can be used scaleX( x ) and scaleY( y ) to only target width or height correspondingly. Values above 1 make the element bigger and between 0 and 1 smaller.
  • skew( x , y ) - skews the element x deg horizontally and y deg vertically. You can specify only one value, but the effect will only affect the X-axis, the y will be set to 0. Just like scale, you can specify this action for the X and Y-axis individually with skewX() and skewY().
  • matrix( scaleX() , skewY() , skewX() , scaleY() , translateX() , translateY() ) - the matrix allows to easily combine all the methods above.

All the previous effects will be applied to the center of the element unless the property transform-origin value is changed. That value can be 1 or 2 percentages or even the following values: top, bottom, right, left and center.

If you tried to explore the code of some of the previous animations shown here, you may notice that we are not using the transform property all the time. However, that does not imply that you can not do the same animations using only transformations. To show that, we created both effects using the transform property. Check below all the alterations needed; you’ll be surprised by how easy it is to do the same effect without changing the HTML structure.

See the Pen previous animations using transform by Patrícia Silva (@patsilva_tese) on CodePen.

Performance of CSS Animations vs Javascript

Animations done through JavaScript are managed on the main thread of the browser where the layout and painting also happen. CSS animations, depending on the properties that are being changed, can occur in a separate thread called the compositor thread. If the browser takes more time on more demanding tasks, main thread animations will be compromised and interrupted, whereas compositor ones won't be affected and will keep going smoothly. So, if you choose Javascript, you are more likely to have missing frames on your animations.

Conclusion

In sum, making animations using CSS and the transform property should be a priority. They are easy to do, especially for those who already get the hang of it and know precisely the goals to achieve. Nonetheless, it's important to be careful regarding animation's excessive use since it can lead to performance issues and cause an overwhelming situation for the user.

Found this article useful? You might like these ones too!

At Imaginary Cloud, we simplify complex systems, delivering interfaces that users love. If you’ve enjoyed this article, you will certainly enjoy our newsletter, which may be subscribed below. Take this chance to also check our latest work and, if there is any project that you think we can help with, feel free to reach us. We look forward to hearing from you!