Performant CSS animations cheatsheet
<main>
<h1>Performant Animations</h1>
<p>Favour using the properties <code>transform</code> and <code>opacity</code> for your animations. You will be surprised by how much you can achieve with only these 2 properties. Below, I demonstrate some of the actions you can do with these properties.</p>
<h2>Size</h2>
<div class="item">
<h3>Width</h3>
<figure>
<div class="container">
<div class="rect widen"></div>
</div>
<figcaption>
Changing width of a rectangle
</figcaption>
</figure>
<p>You can change the width of an element with <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleX()"><code>transform: scaleX()</code></a>.</p>
<pre>
<code class="language-css">.widen {
animation: widen 2s infinite alternate;
}
@keyframes widen {
to {
transform: scaleX(2);
}
}</code></pre>
<p>You can use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale()"><code>transform: scale()</code></a> if you wish to change the width and height together.</p>
</div>
<div class="item">
<h3>Height</h3>
<figure>
<div class="container">
<div class="rect heighten"></div>
</div>
<figcaption>
Changing height of a rectangle.
</figcaption>
</figure>
<p>You can change the height of an element with
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleY()"><code>transform: scaleY()</code></a>.
</p>
<pre>
<code class="language-css">.heighten {
animation: heighten linear 2s infinite alternate;
}
@keyframes heighten {
to {
transform: scaleY(2);
}
}</code>
</pre>
<p>You can use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale()"><code>transform: scale()</code></a> if you wish to change the width and height together.</p>
</div>
<hr>
<h2>Rotation</h2>
<div class="item">
<h3>Directional Rotation</h3>
<figure>
<div class="container rotation">
<img src="img/arrow-right.svg" alt="a pink arrow" class="arrow arrowRight rotate" eleventy:ignore />
</div>
<figcaption>
Rotating right arrow clockwise 90 degrees.
</figcaption>
</figure>
<p>You can change the direction of an element with <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate()"><code>transform: rotate()</code></a>.</p>
<pre>
<code class="language-css">.rotate {
animation: rotate linear 2s infinite alternate;
}
@keyframes rotate {
to {
transform: rotate(90deg);
}
}</code>
</pre>
</div>
<div class="item rotation">
<h3>Sideways Rotation</h3>
<figure>
<div class="container">
<img src="img/arrow-right.svg" alt="a pink arrow" class="arrow arrowRight rotateSideways" eleventy:ignore />
</div>
<figcaption>
This is a right arrow being rotated 360 degrees on Y axis.
</figcaption>
</figure>
<pre>
<code class="language-css">.rotateSideways {
animation: rotateSideways linear 2s infinite alternate;
}
@keyframes rotateSideways {
to {
transform: rotateY(360deg);
}
}</code>
</pre>
<p>This was counter-intuitive for me when I was began learning transformations. I thought it would be <code>rotateX()</code> to get this effect.</p>
</div>
<div class="item">
<h3>Lengthways Rotation</h3>
<figure>
<div class="container rotation">
<img src="img/arrow-up.svg" alt="a pink arrow pointing up" class="arrowUp arrow rotateLengthways" eleventy:ignore>
</div>
<figcaption>
This is an up arrow being rotated 360 degrees on the X axis.
</figcaption>
</figure>
<p>You can rotate an element lengthways with
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateX()"><code>transform:rotateX()</code></a>.
</p>
<pre>
<code class="language-css">.rotateLengthways {
animation: rotateLengthways linear 2s infinite alternate;
}
@keyframes rotateLengthways {
to {
transform: rotateX(360deg);
}
}</code>
</pre>
<p>This was counter-intuitive for me when I was began learning transformations. I thought it would be <code>rotateY()</code> to get this effect.</p>
</div>
<hr>
<h2>Movement</h2>
<div class="item">
<h3>Horizontal Movement</h3>
<figure>
<div class="container">
<img src="img/arrow-right.svg" alt="a pink arrow pointing to the right" class="arrow arrowRight moveHorizontal" eleventy:ignore>
</div>
<figcaption>
Moving right arrow horizontally.
</figcaption>
</figure>
<p>You can move an element horizontally with <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateX"><code>transform:translateX()</code></a>.</p>
<pre>
<code class="language-css">.moveHorizontal {
animation: moveHorizontal linear 2s infinite alternate;
}
@keyframes moveHorizontal {
to {
transform: translateX(150%);
}
}</code>
</pre>
</div>
<div class="item">
<h3>Vertical Movement</h3>
<figure>
<div class="container">
<img src="img/arrow-up.svg" alt="a pink arrow pointing up" class="arrowUp arrow moveVertical" eleventy:ignore>
</div>
<figcaption>
Moving up arrow vertically.
</figcaption>
</figure>
<p>You can move an element vertically with <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateY"><code>transform:translateY()</code></a></p>
<pre>
<code class="language-css">.moveVertical {
animation: moveVertical linear 2s infinite alternate;
}
@keyframes moveVertical {
to {
transform: translateY(30px);
}
}</code>
</pre>
</div>
<div class="item">
<h3>Diagonal Movement</h3>
<figure>
<div class="container">
<img src="img/arrow-up.svg" alt="a pink arrow pointing up" class="arrowUp arrow moveDiagonally1" eleventy:ignore>
</div>
<figcaption>
Moving right arrow diagonally (north-east).
</figcaption>
</figure>
<p> You can move an element direction diagonally by using <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate"><code>transform:translate()</code></a> to move the element horizontally and vertically at the same time. </p>
<pre>
<code class="language-css">.moveDiagonally1 {
animation: moveDiagonally1 linear 2s infinite alternate;
}
@keyframes moveDiagonally1 {
to {
transform: translate(-50%, 50%);
}
}</code>
</pre>
<figure>
<div class="container">
<img src="img/arrow-up.svg" alt="a pink arrow pointing up" class="arrowUp arrow moveDiagonally2" eleventy:ignore>
</div>
<figcaption>
Rotating and moving right arrow diagonally (north-east)</code>.
</figcaption>
</figure>
<p>If you want the element to face in the direction of movement, you need to rotate the element and use <code>translate()</code> to move it in the correct direction.</p>
<p>The order of transformations is important, <code>transform:rotate() translate()</code> and <code>transform:translate() rotate()</code> give different results.</p>
<pre>
<code class="language-css">.moveDiagonally2 {
animation: moveDiagonally2 linear 2s infinite alternate;
}
@keyframes moveDiagonally2 {
0% {
transform: rotate(45deg) translateY(0);
}
100% {
transform: rotate(45deg) translateY(105%);
}
}</code>
</pre>
</div>
<div class="item">
<h3>Moving Closer/Further Away</h3>
<figure>
<div class="container">
<img src="img/train.svg" alt="an outline of the front of a train" class="train scale" eleventy:ignore>
</div>
<figcaption>
Moving train closer and further away.
</figcaption>
</figure>
<p>You can use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale()"><code>transform: scale()</code></a> or <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateZ()"><code>transform: translateZ()</code></a>.</p>
<p>Using <code>transform: scale()</code> is shrinking or enlarging an element. It is kind of cheating! It works well to create a perception of depth for simple movement e.g. straight lines.</p>
<pre>
<code class="language-css">.scale {
animation: scale linear 2s infinite alternate;
}
@keyframes scale {
to {
transform: scale(0);
}
}</code>
</pre>
<p>For more complex movements, you need to make a translation along the Z-axis. The Z-axis is the depth dimension. Using <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate3D()"><code>transform: translate3d()</code></a> will give you complete control of moving an element in all 3 dimensions.</p>
</div>
<hr>
<h2>Visibility</h2>
<div class="item">
<h3>Hide/Show</h3>
<figure>
<div class="container">
<div class="rect visibility"></div>
</div>
<figcaption>
Hiding/showing rectangle.
</figcaption>
</figure>
<p>Use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/opacity"><code>opacity</code></a> to control visibility of an element. You can use it for toggling between states and flashing objects at a particular frequency.</p>
<pre>
<code class="language-css">.visibility {
animation: visibility linear 1s infinite alternate;
}
@keyframes visibility {
to {
opacity: 0;
}
}</code></pre>
</div>
</main> :root {
--element-color: #ff00bf;
--max-width: 600px;
}
html {
box-sizing: border-box;
}
body {
background-color: black;
color: white;
font-family: "Lucida Sans", "Lucida Sans Regular", "Lucida Grande",
"Lucida Sans Unicode", Geneva, Verdana, sans-serif;
}
main {
padding: 1rem 0.25rem;
max-width: var(--max-width);
margin: 0 auto;
}
a {
color: var(--element-color);
text-decoration: none;
}
h1,
h2,
h3 {
width: 100%;
text-align: center;
}
h2 {
text-decoration: underline;
}
hr {
color: white;
}
.item {
display: grid;
width: 100%;
max-width: var(--max-width);
row-gap: 1rem;
margin: 1rem auto;
}
figure {
margin: 0 5px;
}
figcaption {
margin-top: 0.5rem;
text-align: center;
font-size: 0.75rem;
}
pre[class*="language-"] {
overflow: auto;
margin: 0 5px;
}
.container {
height: 100px;
display: flex;
justify-content: center;
align-items: center;
background-color: rgb(0, 53, 199);
box-shadow: rgba(88, 188, 255, 0.5) 0 0 2px 2px;
}
/* animated elements */
.rect {
width: 60px;
height: 30px;
background-color: var(--element-color);
box-shadow: rgba(0, 0, 0, 0.3) 0 0 2px 1px;
}
svg {
fill: var(--element-color);
}
.arrow,
.train {
width: 60px;
}
.arrowUp {
width: 40px;
}
@media screen and (min-width: 600px) {
}
/* animations */
.widen {
animation: widen 2s infinite alternate;
}
@keyframes widen {
to {
transform: scaleX(2);
}
}
.heighten {
animation: heighten linear 2s infinite alternate;
}
@keyframes heighten {
to {
transform: scaleY(2);
}
}
.rotate {
animation: rotate linear 2s infinite alternate;
}
@keyframes rotate {
to {
transform: rotate(90deg);
}
}
.rotateSideways {
animation: rotateSideways linear 2s infinite alternate;
}
@keyframes rotateSideways {
to {
transform: rotateY(360deg);
}
}
.rotateLengthways {
animation: rotateLengthways linear 2s infinite alternate;
}
@keyframes rotateLengthways {
to {
transform: rotateX(360deg);
}
}
.moveHorizontal {
animation: moveHorizontal linear 2s infinite alternate;
}
@keyframes moveHorizontal {
to {
transform: translateX(150%);
}
}
.moveVertical {
animation: moveVertical linear 2s infinite alternate;
}
@keyframes moveVertical {
to {
transform: translateY(30px);
}
}
.moveDiagonally1 {
animation: moveDiagonally1 linear 2s infinite alternate;
}
@keyframes moveDiagonally1 {
to {
transform: translate(-50%, 50%);
}
}
.moveDiagonally2 {
animation: moveDiagonally2 linear 2s infinite alternate;
}
@keyframes moveDiagonally2 {
0% {
transform: rotate(45deg) translateY(0);
}
100% {
transform: rotate(45deg) translateY(105%);
}
}
.scale {
animation: scale linear 2s infinite alternate;
}
@keyframes scale {
to {
transform: scale(0);
}
}
.visibility {
animation: visibility linear 1s infinite alternate;
}
@keyframes visibility {
to {
opacity: 0;
}
} Description
To make CSS animations that have peak performance, you should favour using the properties transform and opacity. You will be surprised by how much you can achieve with only these 2 properties. In this demo I walk through how to perform a range of movements and effects with these properties.
If you would like to learn more about how to write highly performant animations, you can read my article – How to design highly performant animations and micro-interactions.
Dependencies
Scripts
- Prism (Syntax Highlighter) https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/prism.min.js
Stylesheets
- Tomorrow Prism theme https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/themes/prism-tomorrow.min.css