In this tutorial we’ll learn how to create CSS keyframes in JavaScript using JSON and small modules. We’ll be creating this simple interactive demo below that generates a new CSS animation whenever you click on the button.

Click Generate Keyframe to dynamically create a CSS animation

Our example is trivial, but the concepts that we’ll explore are just as useful when customizing the visual feedback in your interactive web applications, simulations and games.

Programattic control of your animations opens up the door to animating information and rewards differently depending on whatever data you have available to you at any given time.

For example - if your user is on some sort of streak you might pay them a subtle nod by slowly increasing size or hue of a reward animation as their streak increases.

Dependencies

Before we begin, we’ll download all of our dependencies up front. After we download our dependencies we will not need an internet connection to finish the tutorial.

mkdir dynamic-animation-tutorial
cd dynamic-animation-tutorial
touch tutorial.js

We use exact versions of our dependencies to help our tutorial last over time as they get updated.

npm install budo@10.0.3 standard@10.0.2 \
create-keyframe@1.0.2 insert-styles@1.2.1 \
stringify-object@3.2.0

The end goal

In a nutshell, we want to dynamically create and modify <style> tags that define animations.

So you might start off with a page that looks like this:

<html>
  <head>
    <!-- Your page starts of like this-->
  </head>
  <body>
   ...
  </body>
</html> 

But then during runtime you’ll insert a style tag into your <head>, which makes your page look something like this:

<html>
  <head>
    <!-- We dynamically create a <style> 
    tag with a CSS keyframe string -->
    <style>
        <!-- You created this style string in code 
        and insert it into your <head> -->
        @keyframe my-generated-keyframe { ... }
    </style>
  </head>
  <body>
   ...
  </body>
</html>  

Now that we know the rough idea behind how our animations work, let’s dive into making one.

Creating our animation

Open your tutorial.js file and start typing out the code:


We start by requireing our dependencies.

stringify-object powers the live preview of our @keyframe preview. create-keyframe and insert-styles are used to create CSS keyframes and insert them into the page.

var stringifyObject = require('stringify-object')
var createKeyframe = require('create-keyframe')
var insertCSS = require('insert-styles')

Next we create the div that will hold our @keyframe preview.

var jsonDisplay = document.createElement('div')
jsonDisplay.style.whiteSpace = 'pre'
jsonDisplay.style.borderRadius = '5px'
jsonDisplay.style.backgroundColor = '#F6F6F6'
jsonDisplay.style.color = '#2B2B2B'
jsonDisplay.style.maxWidth = '500px'
jsonDisplay.style.fontSize = '24px'
jsonDisplay.style.marginTop = '15px'
jsonDisplay.style.fontFamily = 'Avenir'
jsonDisplay.style.padding = '5px'
jsonDisplay.style.boxSizing = 'border-box'

After this we create the div that holds the message that we’re animating.

var userMessage = document.createElement('span')
userMessage.style.fontSize = '48px'
userMessage.style.display = 'block'
userMessage.innerHTML = 'Great Job!'

Next we create a button that when pressed will execute a generateKeyframe function that we will create. This function will be responsible for randomly generating and setting a new animation onto our userMessage span.

var createAnimationButton = 
  document.createElement('button')
createAnimationButton.style.fontSize = '24px'
createAnimationButton.style.cursor = 'pointer'
createAnimationButton.onclick = generateKeyframe
createAnimationButton.innerHTML = 'Generate keyframe'

Now we add all of our tutorial DOM elements into the page.

var appContainer = document.querySelector(
 '#generate-keyframe-animation-tutorial'
) || document.body
appContainer.appendChild(userMessage)
appContainer.appendChild(createAnimationButton)
appContainer.appendChild(jsonDisplay)

Next we create a quick function to generate random colors for us. As you see in the demo above, whenever you hit Generate Keyframe a new random color is created for the animation.

function createRandomColors () {
  return [
    (Math.random() * 255).toFixed(0),
    (Math.random() * 255).toFixed(0),
    (Math.random() * 255).toFixed(0),
    1
  ]
}

And now for the meat of our little app. We first generate some random colors that we’ll use for our animation.

We then randomly determine a shakeDistance, which is the amount that our userMessage slides from left to right.

After this we create an @keyframe object in JSON, convert it into CSS using create-keyframe and then insert it into the page using insert-styles.

Lastly we update our JSON preview div and set the animation for our span to the newly generated animation.

function generateKeyframe () {
  var randomColors = createRandomColors()

  var shakeDistance = Number(
   (Math.random() * 70).toFixed(0)
  ) + 30

  var cssKeyframe
  cssKeyframe = {
    0: {
      color: 'black'
    },
    20: { transform: `translateX(${shakeDistance}px)` },
    60: { transform: `translateX(-${shakeDistance}px)` },
    75: {
      color: `rgba(${randomColors.join(', ')})`
    },
    100: { color: 'black' }
  }
  var keyframeObj = createKeyframe(cssKeyframe)
  insertCSS(keyframeObj.css, {id: 'animaton-tutorial-keyframe'})

  jsonDisplay.innerHTML = `@keyframe ${keyframeObj.name} ` +
   stringifyObject(cssKeyframe, {indent: '  '})
  userMessage.style.animation = keyframeObj.name + ' ease 3s infinite'
}

generateKeyframe()

Nice work!

And just like that you’ve dynamically generated CSS @keyframe animations.

Go forth and create animations using code and data. And definitely shoot me a tweet whenever any unique or interesting use cases come to mind.

Also, feel free to make use of the commented source code on GitHub.

Til’ next time,

- CFN