Master of the universe

Create Complex Animations With Keyframes: CSS Animations


Cascading Style Sheets (CSS) animations have become a powerful tool for web developers to create captivating user interfaces and enhance the overall user experience of a website. CSS animations enable you to control how elements on a web page change over time, adding a dynamic and engaging layer to your design. A fundamental component of creating complex CSS animations is the use of keyframes.

In this article, we will explore how to create complex animations with keyframes in CSS. We will cover the essentials, such as understanding and defining keyframe rules, applying animations to elements using the animation property and individual animation properties, and diving into advanced techniques for animations.

Understanding Keyframes

What are Keyframes?

Keyframes in CSS animations serve as building blocks for defining how an animation should progress over time. Keyframes denote the various states of an animation, indicating how the property of an element should change at specific points during the duration of the animation. This allows you to create intricate animations that evolve smoothly and continuously.

In essence, keyframes define the starting point, ending point, and any intermediate steps of an animation, allowing you to achieve fluid and complex visual effects.

Creating Keyframe Rules

To create keyframe rules, you'll need to use the @keyframes at-rule in CSS. The syntax for defining keyframe rules consists of the @keyframes keyword, followed by the name you assign to the animation, and a set of curly braces {} containing the specific keyframes (percentage values) indicating the steps of the animation.

Here's a basic example of defining a keyframe rule with various animation states:

@keyframes fadeIn {
  0% {
    opacity: 0;
  50% {
    opacity: 0.5;
  100% {
    opacity: 1;

In this example, we're creating an animation named fadeIn that alters the opacity of an element. At the beginning of the animation (0%), the element is fully transparent (opacity: 0). At the halfway point (50%), the element is semi-transparent (opacity: 0.5), and by the end of the animation (100%), the element is fully opaque (opacity: 1).

You can also use the from and to keywords as shorthand alternatives to 0% and 100% keyframes:

@keyframes fadeIn {
  from {
    opacity: 0;
  to {
    opacity: 1;

This simplified version illustrates a basic fade-in animation that progresses from fully transparent to fully opaque.

Applying Animations to Elements

Once you've defined the keyframe rules for your animation, you need to apply the animation to the desired HTML elements. You can achieve this by using the animation shorthand property or individual animation properties.

Using the animation Property

The animation property is a shorthand for specifying a set of individual animation-related properties in a concise manner. It allows you to define the animation name, duration, timing function, delay, iteration count, direction, fill mode, and play state all at once.

Here's the syntax for applying the animation property to an HTML element:

selector {
  animation: animation-name animation-duration animation-timing-function animation-delay animation-iteration-count animation-direction animation-fill-mode animation-play-state;

Using the fadeIn keyframe rule from the previous section, you can apply the animation using the animation shorthand property like this:

.example-element {
  animation: fadeIn 2s ease-in-out 1s 1 normal forwards running;

In this example, the .example-element class has an animation that will fade in the element. The animation uses the fadeIn keyframe rule, lasts for 2 seconds, has an ease-in-out timing function, has a 1-second delay before starting, runs only once (animation-iteration-count: 1), follows a normal direction (animation-direction: normal), keeps the final state of the animation (animation-fill-mode: forwards), and runs immediately (animation-play-state: running).

Individual Animation Properties

Instead of using the animation shorthand property, you can also specify each animation-related property individually. This approach can be beneficial when you want to be more explicit about each property, or if you want to override a specific animation property without altering others.

Here's an example of applying the fadeIn keyframe rule using individual animation properties:

.example-element {
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-delay: 1s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-play-state: running;

This code achieves the same result as using the animation shorthand property. Each of the animation-related properties is specified explicitly, providing a clear overview of the individual components of the animation.

Advanced Animation Techniques

To truly harness the power of keyframe animations, understanding some advanced techniques can help you create engaging effects and intricate animations. In this section, we will explore how to work with multiple keyframes, animate multiple CSS properties, and chain/group animations together.

Multiple Keyframes and Intermediate States

Keyframe animations become more complex and diverse when you introduce additional keyframes or intermediate states within your animation. By adding more keyframes, you can define additional stylish effects or create more nuanced movement for your animations.

Let's consider the following example, which demonstrates an animation that moves an element in a diagonal path while bouncing:

@keyframes diagonalBounce {
  0%, 100% {
    transform: translateY(0) translateX(0);
  25%, 75% {
    transform: translateY(-50px) translateX(50px);
  50% {
    transform: translateY(0) translateX(100px);

In this diagonalBounce keyframe rule, we've defined multiple keyframes (0%, 25%, 50%, 75%, and 100%) to create a more complex animation that progresses through each state. This animation moves the element 100 pixels to the right while bouncing vertically.

Animating Multiple Properties

Another advanced technique to create complex animations is animating multiple CSS properties within a single keyframe rule. This approach allows you to manipulate several aspects of an element simultaneously, creating multifaceted animations.

Here's an example showcasing how to animate both the opacity and transform properties together:

@keyframes rotateAndFade {
  0% {
    opacity: 0;
    transform: rotate(0);
  50% {
    opacity: 1;
    transform: rotate(180deg);
  100% {
    opacity: 0;
    transform: rotate(360deg);

In this example, the rotateAndFade keyframe rule animates both the opacity and rotation of an element simultaneously. The element begins with an opacity of 0 and gradually fades in as it rotates 180 degrees. Once it reaches the 50% keyframe, it starts to fade out as it continues to rotate up to 360 degrees, creating a fluid and synchronized combined animation.

Chaining and Grouping Animations

Sometimes, you may want to apply multiple animations to a single element, either one after another (chaining) or concurrently (grouping). Mastering techniques to chain and group animations can lead to incredibly dynamic and visually impressive effects.

Chaining Multiple Animations on a Single Element

Chaining multiple animations involves setting up one animation to begin after the previous one has finished or is paused. You can accomplish this by using the animation-delay property to set a specific starting point for each subsequent animation.

Consider the following example, where we chain the rotateAndFade and diagonalBounce animations:

.example-element {
    rotateAndFade 2s ease-in-out forwards,
    diagonalBounce 4s linear 2s forwards;

In this case, the rotateAndFade animation applied to .example-element lasts for 2 seconds and is followed by the diagonalBounce animation, which takes 4 seconds to complete. By setting the animation-delay of diagonalBounce to 2s, we ensure that it starts immediately after rotateAndFade has finished.

Grouping Animations Using animation-delay and animation-iteration-count

Grouping animations allows you to run several animations at the same time. You can achieve this by specifying different values for the animation-delay and animation-iteration-count properties.

Here's an example that groups the rotateAndFade and diagonalBounce animations together:

.example-element {
    rotateAndFade 4s ease-in-out infinite,
    diagonalBounce 4s linear 0s 2 alternate;

In this example, the rotateAndFade animation takes 4 seconds to complete and repeats indefinitely (animation-iteration-count: infinite). At the same time, the diagonalBounce animation runs with no delay (animation-delay: 0s), takes 4 seconds to complete, and runs twice (animation-iteration-count: 2) in an alternating direction (animation-direction: alternate).

Using Animation Events

To achieve seamless integration between your CSS animations and JavaScript code, you can utilize animation-related JavaScript events. These events allow you to listen for and handle specific phases in the animation lifecycle, such as when an animation starts, repeats, or ends. These events include animationstart, animationiteration, and animationend.

Overview of Animation-Related JavaScript Events

  1. animationstart: This event triggers when the animation starts playing for the first time (including when the page loads, if the animation has animation-play-state: running).
  2. animationiteration: This event occurs when an animation completes a cycle and starts a new iteration.
  3. animationend: The event triggers when the animation finishes its last iteration.

Example Code for Listening to and Handling Animation Events in JavaScript

The following example demonstrates how you can listen for and handle the animationstart, animationiteration, and animationend events using JavaScript:

<div class="example-element">Chained Animations</div>

  const animationElement = document.querySelector('.example-element');

  animationElement.addEventListener('animationstart', (event) => {
    console.log('Animation started:', event.animationName);

  animationElement.addEventListener('animationiteration', (event) => {
    console.log('Animation iterated:', event.animationName);

  animationElement.addEventListener('animationend', (event) => {
    console.log('Animation ended:', event.animationName);

In this example, three event listeners are added to the .example-element element, which log the current animation name when each event occurs. This allows you to track the animation lifecycle and perform additional actions, such as starting another animation or updating the element's content.

Best Practices and Optimization

Creating stunning animations is only part of the process; it's essential to consider performance and ensure that your animations are accessible and user-friendly. In this section, we'll discuss some best practices and optimization techniques for complex animations with keyframes.

Performance Considerations

To ensure that your animations run smoothly on various devices and screens, consider the following performance optimization tips:

  1. Use the will-change property: Use the will-change property to inform the browser that an element is likely to undergo an animation. This optimization enables the browser to prepare for the animation beforehand, yielding better performance. However, avoid overusing this property, as excessive usage may lead to less optimized rendering.
    .example-element {
      will-change: transform, opacity;
  2. Leverage the transform property: For smoother animations, focus on animating the transform property instead of other properties like width, height, top, or left. Animating transform properties like translate, rotate, or scale is more efficient and can help minimize layout recalculations.
  3. Avoid animating expensive CSS properties: Some properties, such as box-shadow, background-color, or border-radius, can negatively impact the performance of your animations. Consider using alternative properties or techniques for similar visual effects without sacrificing performance.

Accessibility and Usability

Creating accessible and user-friendly animations is crucial for ensuring a positive experience for all users. Here are some recommendations for maintaining accessibility and usability in your animations:

  1. Respect user preferences: Certain users may prefer reduced motion due to vestibular disorders or other conditions. Detect user preferences by using the prefers-reduced-motion media query, and adjust your animations accordingly.
    @media (prefers-reduced-motion: reduce) {
      .example-element {
        animation: none !important;
  2. Ensure animations don't interfere with functionality: While complex animations can enhance the user experience, make sure they don't obstruct or hinder the core functionality of your web page. Keep animations subtle and avoid using them as a distraction or causing confusion.
  3. Provide accessible alternatives: For users who rely on screen readers or keyboard navigation, providing an accessible alternative to animations or content that relies on complex animations can ensure that everyone can interact with your website effectively.


Mastering the use of keyframes in CSS animations is crucial for creating intricate and engaging web experiences. From understanding how keyframes define animation states to applying advanced techniques for chaining and grouping animations, these skills can significantly enhance your web development toolkit.

By maintaining a focus on performance optimization and accessibility, you can ensure that your complex animations are both visually stunning and functional for all users. As you continue to leverage the power of keyframes and complex animations, you'll not only create captivating user interfaces but also contribute to a more inclusive and enjoyable web experience for everyone.

Frequently Asked Questions

What is the difference between CSS animations and transitions?

CSS animations and transitions both enable changes in an element's CSS properties over time. The primary difference is that animations use keyframes to define the intermediate states of an animation, offering more control and flexibility, while transitions only allow altering from an initial state to a final state.

Can I control the speed of the animation at different keyframes?

Yes, the speed of an animation at different keyframes can be controlled with the animation-timing-function property. By setting the animation-timing-function with cubic-bezier, steps, or a keyword (e.g., ease, linear, ease-in), you can influence the rate of change between keyframes, creating custom easing effects.

How can I make an animation run indefinitely?

You can make an animation run indefinitely by setting the animation-iteration-count property to infinite. This ensures that the animation will repeat continuously without stopping.

Can I apply multiple animations to one element?

Yes, you can apply multiple animations to a single element using a comma-separated list of animation properties, chaining them one after another, or running them concurrently. By adjusting the animation-delay and animation-iteration-count properties, you can create complex combinations of animations on a single element.

How do I pause or stop a running animation?

You can pause or stop a running animation by using the animation-play-state property. By setting the property to paused, the animation will stop at its current state. To resume the animation, switch the animation-play-state back to running.

Sign up for the Artisan Beta

Help us reimagine WordPress.

Whether you’re a smaller site seeking to optimize performance, or mid-market/enterprise buildinging out a secure WordPress architecture – we’ve got you covered. 

We care about the protection of your data. Read our Privacy Policy.