Editor’s note: This article was last updated 12 July 2022 to include additional examples.
In this article, we’ll learn how to create lightweight, scalable animations using SVGs with CSS. Although we’ll use Sass for the demos, CSS will also work. Let’s get started!
- Common use cases for animating SVG with CSS
- How to prepare SVGs for animation
- Applying CSS to SVGs
- What can you animate with CSS?
- Other tools for animating SVGs
Common use cases for animating SVG with CSS
Before we jump into the code, let’s review some practical ways to use animated SVGs.
Animated SVGs are great for icons that indicate micro-interactions and state changes. They are also helpful when guiding a user to the next action, like in an onboarding tour. Common use cases include loading, uploading, menu toggling, and playing and pausing a video.
Illustrations are another common use case. They can be included in a product as a blank state, demonstrating what to do to generate data on a dashboard. Other popular use cases include animated emojis and stickers. There are also animated spot illustrations, which help to brighten up landing pages.
How to prepare SVGs for animation
Since it’s easier to start out with simplified SVG code, the first part of animating SVGs is preparing them. You can do so by following the steps below:
Optimize the SVG code
When an SVG is created, it often has some extra, unnecessary code, so it’s important to optimize it. You can use a tool like SVGOMG that reduces the file size and removes any unnecessary tags and metadata.
Create intentional groupings
If needed, you can create intentional groupings by opening the SVG in a code editor and taking note of the
<g> elements, which are used to group SVG elements. If you want to animate a group of elements together, wrap them in
<g></g> and name them with a class or ID.
If we want to style multiple paths in the same way, we could also consider converting ID names to class names.
Beware of stacking order
It seems counter-intuitive, but shapes listed last will be pasted over the aforementioned shapes. If we want a shape to appear in the background, we must ensure that it is listed at the top of the SVG code. SVG shapes are painted in order from top to bottom.
Set SVG styling to the preferred, initial state
SVGs have presentation attributes that are similar to CSS styles but are set directly on the SVG. A common example is a
fill color. Since these styles are set on the SVG, you may assume that they hold a lot of weight by the browser. As it turns out, any CSS or Sass we set externally will naturally override the SVG styling without a need for an
However, be mindful of what is set on the SVG so you can prepare for what’s shown during page load. For example, a slow-loading page will display a flash of the SVG before the CSS styles get applied. I recommend you leave in the width and height to avoid this; Sara Soueidan does a good job of explaining flash of unstyled SVGs in her blog post on the subject.
Applying CSS to SVGs
Now that we’ve tidied the SVG, let’s explore a few options for adding the CSS.
There are a few considerations when it comes to applying CSS to an SVG. One limitation is that we can’t use an external stylesheet to apply styling to an externally linked SVG.
Embedding the SVG code inline in the HTML makes the SVG element and its contents part of the document’s DOM tree, so they’re affected by the document’s CSS. This method is my favorite because it keeps the styles separate from the markup.
In reviewing the other options below, we’ll see they’re all entwined. If you’re using Rails, there are some gems that can automatically embed SVGs into views. So, in your code, you can simply reference the external SVG, then it’ll get embedded when compiled. An added benefit of this method is that inlining the SVG means there’s one less HTTP request, improving performance:
We can add CSS styles in a
<style> tag, nested within the
If you’d like to keep the styling referenced in the SVG, but not actually include it within the SVG, you can use the
<?xml-stylesheet> tag to link to an external style sheet from the SVG:
CSS may also be set on an element using inline style attributes
More great articles from LogRocket:
- Don't miss a moment with The Replay, a curated newsletter from LogRocket
- Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
- Use React's useEffect to optimize your application's performance
- Switch between multiple versions of Node
- Discover how to animate your React app with AnimXYZ
- Explore Tauri, a new framework for building binaries
- Compare NestJS vs. Express.js
What can you animate with CSS?
You can animate lots of things with CSS. For one, you can animate CSS properties with values that can change over time using CSS animations or CSS transitions. For a full list of these properties, check out the MDN Web Doc for a list of animatable CSS Properties. To spark some inspiration, let’s review a few demos.
There are two main types of animations we’ll cover, and they differ by the amount of control they provide.
The first SVG animation we’ll create is a rotating loader, like the ones we usually see on the loading screens of applications. We start by setting up the SVG, which is a ring with a darkened quadrant.
We give the SVG an ID of
loading-spinner, then define the animation and transition. The animation references the name of the
@keyframes, where the
transform: rotate is set to go from
0 degrees to
360 degrees, a full rotation. That’s all it takes to make this spinner come to life!
#loading animation: loading-spinner 1s linear infinite @keyframes loading-spinner from transform: rotate(0deg) to transform: rotate(360deg)
Wanting something smoother? SVGs support gradients, so you can achieve a smoother effect using the same Sass but with an SVG that has a gradient applied to the ring, see it defined as
Now, let’s play around with
transform: scale to create this morphing bar loading icon.
The SVG consists of three equally sized rectangles spaced apart evenly. IDs have been added per element, for the SVG and all three
<rect> elements, so they can be easily targeted with the Sass.
The Sass applies the animation to each bar. The keyframes tell the bars to change scale along the Y axis in four places in the timeline : on onset, a quarter of the way in, halfway, and then three-quarters of the way in.
The first number in the animation denotes the animation length, while the second one sets the delay. Since I want these bars to morph in size at different times, I’ve added different delays for each:
#loading-bar &-left animation: loading-bar-morph 1s linear .1s infinite transform-origin: center &-middle animation: loading-bar-morph 1s linear .2s infinite transform-origin: center &-right animation: loading-bar-morph 1s linear .4s infinite transform-origin: center @keyframes loading-bar-morph 0% transform: scaleY(1) 25% transform: scaleY(0.3) 50% transform: scaleY(0.7) 75% transform: scaleY(0.15)
transform-origin: center tells the transform to scale from the center of the bar; otherwise, it would scale from the top down and appear as if the bars are drilling into the ground. Test it out, and you’ll see what I mean.
By default, an SVG is positioned at the
(0, 0) point, in the top-left corner. This is a key difference if you’re used to working with HTML elements, whose default transform-origin is always at
Line drawing animation
We can add a line-drawing effect to make the SVG appear as if it’s being drawn. Since it relies on strokes, it requires an SVG with lines. I’ll walk you through how it’s done for a single line, and then you’ll know how to do the rest.
First, apply a dashed stroke to the lines using
stroke-dasharray. The number represents the length of the dashes in pixels. You’ll want it to be the length of the line:
#line stroke-dasharray: 497
stroke-dashoffset to reposition the dash along the line. Make it as long as the line itself so it looks like a solid line. This is how the final frame of the animation will look:
#line stroke-dasharray: 497 stroke-dashoffset: 497
Now, it’s ready to be animated. Let’s add keyframes that animate the
stroke-dashoffset so it goes from the full offset with no stroke visible to a
0px offset, a solid stroke. Note the
forwards in the animation property.
This is an
animation-fill-mode that tells the animation to stay in its final end state once played. Without it, the animation would then return to its first frame as its final resting spot:
#line stroke-dasharray: 497 stroke-dashoffset: 497 animation: draw 1400ms ease-in-out 4ms forwards @keyframes draw from stroke-dashoffset: 1000 to stroke-dashoffset: 0
Let’s use Animista’s heartbeat animation to demonstrate animating an illustration to have a pulse effect. Animista is a great resource for premade CSS animation effects that you can reuse and iterate on.
For this beating heart, a few animations are triggered on hover. There’s a 110 percent scale change on the heart, and the eyes get smaller, the mouth gets bigger, blush appears, and the heart pulses:
#smiley-love #smiley &-blush display: none a display: inline-block &:hover #smiley transform: scale(1.1) transform-origin: center -webkit-animation: heartbeat 1.5s ease-in-out infinite both animation: heartbeat 1.5s ease-in-out infinite both &-blush display: inherit &-eye-left transform-origin: center transform: scale(.7) translate(-8px) &-eye-right transform-origin: center transform: scale(.7) translate(8px) &-mouth transform: translateY(-22px) scale(1.6) transform-origin: center /* ---------------------------------------------- * animation heartbeat * Generated by Animista on 2019-3-24 18:51:13 * w: http://animista.net, t: @cssanimista * ---------------------------------------------- */ @-webkit-keyframes heartbeat from -webkit-transform: scale(1) transform: scale(1) -webkit-transform-origin: center center transform-origin: center center -webkit-animation-timing-function: ease-out animation-timing-function: ease-out 10% -webkit-transform: scale(0.91) transform: scale(0.91) -webkit-animation-timing-function: ease-in animation-timing-function: ease-in 17% -webkit-transform: scale(0.98) transform: scale(0.98) -webkit-animation-timing-function: ease-out animation-timing-function: ease-out 33% -webkit-transform: scale(0.87) transform: scale(0.87) -webkit-animation-timing-function: ease-in animation-timing-function: ease-in 45% -webkit-transform: scale(1) transform: scale(1) -webkit-animation-timing-function: ease-out animation-timing-function: ease-out @keyframes heartbeat from -webkit-transform: scale(1) transform: scale(1) -webkit-transform-origin: center center transform-origin: center center -webkit-animation-timing-function: ease-out animation-timing-function: ease-out 10% -webkit-transform: scale(0.91) transform: scale(0.91) -webkit-animation-timing-function: ease-in animation-timing-function: ease-in 17% -webkit-transform: scale(0.98) transform: scale(0.98) -webkit-animation-timing-function: ease-out animation-timing-function: ease-out 33% -webkit-transform: scale(0.87) transform: scale(0.87) -webkit-animation-timing-function: ease-in animation-timing-function: ease-in 45% -webkit-transform: scale(1) transform: scale(1) -webkit-animation-timing-function: ease-out animation-timing-function: ease-out
Let’s do another; for this example, I animated the drops on this image of a popsicle by changing their position using
transform: translate. To make them disappear, I animated the
opacity. Now, it looks like it’s a hot summer day!
Let’s create a hamburger menu using SVGs; the animations will be triggered when a user hovers over the menu:
Let’s break down the code above. First, we set up a hamburger SVG with the
rect element and drew three rectangles. We gave the three
rect elements classes of
The core of the animation takes place on hover. When a user hovers, we alter the positions of the rectangles and rotate the
bottom rectangles by 45 percent and -45 percent, respectively. We also set the opacity of the
middle rectangle to
Fade-in and fade-out text
Another cool animation is a fade-in and fade-out text animation:
Here, we set up an text-based SVG using the
text element, defined a
fadeIn animation that will toggle the opacity of the text between
1, and applied the
fadeIn animation to the SVG.
Wavy SVG text
The final demo is a wavy text animation where each letter in the world will go up and down to look like the motion of a wave. We could also call this animation a bouncy text animation.
For the SVG, we use the
text element to define each letter of the word wavy. We push the letters down by
translateY. Later, we’ll make it pop up as part of the wave motion. To complete the effect, we define an animation called
wavyText, and we delay the animation of each letter so they pop up one after the other.
Other tools for animating SVGs
While we can animate SVGs with CSS, there are other tools we can use to handle and create animations. SVG animations can get a little complicated, but the following tools make it extremely simple for us to animate SVGs.
Now that you know a few different ways to animate SVGs with CSS, I hope you’re inspired to create your own animations for the web! It’s fun to bring static SVGs to life with just a few lines of CSS.
Once you get the hang of a few tricks, it’ll be easier to tackle the more complicated animations. There are endless amounts of inspiration online and on sites like CodePen. Happy animating!
Is your frontend hogging your users' CPU?As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — Start monitoring for free.