As an entertainment medium, the web requires a judicious use of special effects to catch and hold interest. In contrast to other media formats, however, the web is limited by bandwidth. If we can find ways to make interesting effects with less data sent over the wire, we all win.
In this article, I’m going to talk about techniques to do more with some simple SVG tricks. In the interest of brevity, I shall assume readers have a rudimentary knowledge of SVG, so I will not explain the more basic concepts.
At the same time, to keep the code more easily understandable, I’ll avoid various optimizations so that I don’t have to explain them. This means the code will at times be more verbose than necessary, but recognize the verbosity is in the service of clarity.
Z-indexing in SVG
The following snippet of SVG code represents a circle:
<circle cx="50" cy="50" r="25" fill="#ff0000" />
As do these:
<circle cx="50" cy="50" r="25" fill="#ffff00" /> <circle cx="50" cy="50" r="25" fill="#ffffff" />
If you have the first two circles in an SVG, you will see a single yellow circle. If you have all three, you should see nothing — assuming the SVG they are in is white.
The reason for this is SVG’s z-indexing rules, which dictate that when any two graphical elements occupy the same space, the one represented later in the XML tree that the SVG is described by will be given a higher
z-index. The white circle is at the same position as the yellow and covers it precisely.
r attribute on each circle represents its radius. Thus, if you want to have layered circles where you can see the circles underneath, you might do so by increasing the radius, like so:
If you did not have the white circle, it would look like you had a yellow circle with a thick red border or stroke. The same principle applies to other graphical elements in SVG.
Let’s suppose we put the following rectangle in between the white and yellow circle.
<rect x="25" y="25" width="50" height="50" fill="#ff00ff" />
y are half the
cy of the circle — because circles are drawn from the center out, and rectangles are drawn from the top left. It will look like this:
And finally, I will put another rectangle in between our previous rectangle and the white circle and rotate it to make a simple star shape:
<rect x="25" y="25" width="50" height="50" fill="#ff00ff" transform = "rotate(45 50 50)"/>
50 values represent the center of the rectangle, which is, of course, the same value as the
cy of our circle.
I think at this point we have enough little areas to play with that we can see about making some interesting effects with animation.
One of the easiest ways to animate things in SVG is to use
animateTransform, which animates a transformation attribute on its target element. In other words, if I put an
animateTransform element as a child of one of these rectangles, I can animate the transform attribute, which we used in our earlier example to rotate our last
If we add the following
animateTransform as the child of the last rectangle…
<animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" dur="10s" repeatCount="indefinite" />
…we will cause that rectangle to rotate a full 360 degrees every 10 seconds indefinitely.
The first number of the
from attribute is from how many degrees it should be rotated at the start of the animation; the first number of the
to is how many degrees it should be rotated at the end of the animation. And if we are doing this, we can remove the original transform attribute on the rectangle, as it is rendered redundantly. Like so:
animate allows you to animate less complicated attributes than the transform attribute, but in the same manner.
As an example, let’s add the following
animate element as the child of our rectangle that has the
<animate attributeName="fill" values="#ff0000; #ffff00; #ff00ff;" dur="10s" repeatCount="indefinite" />
As an example of how the other properties of the animation — like its duration and the number of times to repeat it — can create interesting effects, take a look at this layering of circles.
Each circle has a different duration of animating the fill, the number of times it repeats is set so that they should stop at different times — all except the inner circle, the last in the XML tree, which should have its fill animated forever.
As for how you can animate other SVG properties, the following example animates the
cx property of a number of layered circles. The duration is off by a bit for each one, and the starting time is such that the bottom layer starts first, the top layer starts last, and they all finish one after the other.
fill property is set to
freeze on the animation, which means the attribute will end up with the value that ends the animation (in this case,
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
One last thing to note about these animations is that transparent is a color — this fact will be of use in the next section.
Layering and timing animations
Look at the following animation:
What’s happening here is that there are 18 circles in the SVG. Twelve of the circles are placed along the length of the SVG in pairs — that is to say, there are two circles at
cx="100" on the x radius, two circles at
cx="200", and so forth. Here is the code for the first pair of circles:
<circle cx="100" cy="50" r="30" fill="url(#image1)"></circle> <circle cx="100" cy="50" r="30" fill="#ffffff"> <animate attributeName="fill" values="#ffffff;transparent; " begin="6.1s" dur="0.1s" fill="freeze" repeatCount="1" /> </circle>
Because these two circles sit in the same place, the one that comes later in the markup tree has the higher z-index. So the circle with a fill color of white sits on top of a circle that is filled by an image.
But that white-colored circle has an animation that makes it transparent, meaning you can see the image in the circle underneath when the animation is finished.
Finally, there are six circles that start off at the same location —
cy="50" — and are animated along their
cx. Each one of these circles stops somewhere, covering one of the white circles that, in turn, cover the circle with an image in it.
The white circle animations start after the six circles are done moving to their respective
cx positions. Then, the six circles have an animation on their fill to move from either yellow or red to transparent. Of course, when they are done animating, the white circles are already done animating; therefore, we see the circles with images in them after the fill color of the top image becomes transparent.
In conclusion, with SVG’s z-indexing and properly timed animations, it is pretty simple to construct advanced effects through simple markup patterns that catch the user’s attention.
LogRocket: Full visibility into your web and mobile apps
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.