Animating SVG Gradients
SVG gradients are so handy. We can fill complex shapes and create depth and character for our artwork all while having access to it in the DOM.
Within SVG linear and radial gradient elements there are several attribute options available for thorough customization. Animating these gradients takes this customization even further and presents a unique opportunity that can be used to further communicate something to our users.
This article will cover the basics of SVG gradients and getting started with
<animate>, and then dive into some demos for further understanding.
Basic SVG support is present across desktop and mobile browsers, going at least two versions back across the board for desktop.
Concerning SVG SMIL animation (animating within the SVG element itself) specifically there is no support in IE, IE mobile, or Opera Mini, but strong support in current and at least one version back in Chrome, Firefox, Safari, Opera, and on mobile.
Before we get started with animation, it’s important to have a basic understanding of how SVG gradients work.
Gradients are one of many paint server options we have available to use when we wish to add color to the fills and strokes of SVG. The idea here is that we can define gradients within our SVG but they have no visual output until we call on them with the use of the “fill” and/or “stroke” attributes.
The basic structure of a very simple linear SVG gradient looks something like this:
<svg> <defs> <linearGradient id="greenGradient"> <stop offset="0" stop-color="#b2ed9d" /> <stop offset="100%" stop-color="#569b3d" /> </linearGradient> </defs> <rect width="600" height="150" fill= "url(#greenGradient)" /> </svg>
The gradient details are written within the
<defs> element, but would have no output within our work until we call on it using its unique ID. At this point we would also add the shape within the same
<svg> element, but outside of the
<stop> nodes represent the color selections and their locations on our mapped gradient, which we will discuss further in the following section.
The attribute values for
<radialGradient> allow us to specify the colors and coordinates of our gradients.
Here is a quick look at the attributes that will be used in the demos to follow:
A gradient requires a unique ID in order for it to be called on through “fill” and “stroke” attributes.
x1, x2, y1, y2
The values within the x1, x2, y1, y2 attributes specify the start and end coordinates for linear gradients along the appropriate axis. These values default to “0” if left unspecified, except for x2 which defaults to “100%”.
cx, cy, r, fx, fy
Radial gradient attributes are similar to those of linear, except our coordinates will be handled much differently. Instead of being based on a straight line, these gradients will be mapped circularly.
cx, cy, and r (radius) define the outermost circle for the gradient, with this outer perimeter being the 100% stop point. fx and fy define the focal point of the gradient, with the 0% stop mapping to these values.
Within the gradient element itself we include the
<stop> nodes. The attribute values within
<stop> nodes define the colors for our gradient, where they should be placed, and any opacity that we want applied.
The offset property indicates where the gradient stop is located. For linear gradients this location will be a distance along the gradient line, for radial gradients it will be a distance from the focal point to the edge of the mapped circle.
stop-color indicates what color will be used at the correlating stop point, and stop-opacity sets an opacity at this same point. Depending on how many stops we wish to use we can choose between creating subtle, gradual color changes with only a few stops, or create stripes with several closely mapped stops.
<animate> element will allow us to select gradient attributes and properties and then assign different values to them over a specified duration of time. In short, we can move them! The
<animate> element will reside within the element we wish to animate. Here is the structure for a basic animation on a rectangle:
<svg> <rect x="0" y="20" width="100" height="100"> <animate attributeName="x" from="0" to="400px" dur="5s" repeatCount="indefinite" /> </rect> </svg>
The animation will move the rectangle along the x axis 400px pixels from its starting point. The animation will complete within 5 seconds, and repeat indefinitely.
<animate> element we will use attributes to select our target and specify the details of the animation. Here is a look at the specific attributes we will focus on in the demos:
attributeName defines the name of the target attribute to be animated. In taking another look at the animation code above, the attributeName value is “x” so that we can target and animate our shape on the x axis.
The “to” and “from” attributes indicate the initial and final value of the targeted attribute.
<values> attribute we can create a list of values separated by semicolons, and the animation will apply these values in order over the duration of the action.
By including this attribute any “from” or “to” values within the same
<animate> element will be ignored, meaning that it takes the place of these values once included so there is no need for them.
The duration defines within what time span the animation should complete.
While “fill” often refers to the interior color of SVG, it has a different meaning in the context of an
<animate> attribute. We can set a value of “freeze” within this attribute so that the animation freezes once it is complete and does not restart.
The repeatCount attribute specifies the number of times an animation should take place. This value can be either a number, or “indefinite”.
To target gradients specifically we need to have an idea of what properties we would like to animate, like the stop-color, offset, and/or the specific coordinates.
When we reviewed the code for the moving rectangle animation above the
<animate> element resided within the shape’s element, the
<rect>. In order to animate gradient stops we place the
<animate> element within the specific
<stop> we intend to animate. To animate an attribute directly within the a
<radialGradient> element, like coordinates for example, we position
<animate> within the gradient element, but outside of the
Here’s a look at the structure for an animation on the stop-color of a
<stop offset="<value>" stop-color="<color>"> <animate attributeName="stop-color" from=”<color>” to=”<color> dur="<duration>" repeatCount="indefinite" /> </stop>
To demonstrate the possibilities of animating SVG gradients we will look at some potential effects for a fictional camping site. The demos consist of animated gradients on fire, trees, and a skyline.
Demo 1: Fire
Within the fire SVG we are targeting two flames to fill and animate, and as mentioned all the details are listed within a
<defs> element in the
<defs> <radialGradient id="smallGradient" fy="90%"> <stop offset="0%" stop-color="#f4c708"></stop> <stop offset="100%" stop-color="#f7e69a"></stop> <animate attributeName="fy" dur="700ms" from="90%" to="0%" repeatCount="indefinite" /> </radialGradient> <radialGradient id="largeGradient" fy="90%"> <stop offset="0%" stop-color="#ff8806"></stop> <stop offset="100%" stop-color="#d9574a"></stop> <animate attributeName="fy" dur="700ms" from="90%" to="0%" repeatCount="indefinite" /> </radialGradient> </defs>
There are two radial gradients, “smallGradient” and “largeGradient”. The same animation is applied to each gradient targeting the fy coordinate point and moving it from 90% to 0% within 700ms. The animation is set to take place indefinitely.
The assignment of these gradients is done by adding the gradient ID to the “fill” of the shape via a URL, for example:
Demo 2: Trees
For the trees demo we will be adding the animation to the gradient stop-color. There are two gradients to represent different colors for the trees, one with dark shades of green and one with light. Each animation is essentially the same, the only difference being the colors used.
<defs> <linearGradient id="darkGradient" x1="30%" y1="70%"> <stop offset="0%" stop-color="#0b2d13"> <animate attributeName="stop-color" values="#0b2d13; #79c98c" dur="3s" fill="freeze" /> </stop> <stop offset="100%" stop-color="#79c98c"> <animate attributeName="stop-color" values="#79c98c; #0b2d13" dur="3s" fill="freeze" /> </stop> </linearGradient> <linearGradient id="lightGradient" x1="30%" y1="70%"> <stop offset="0%" stop-color="#054f16"> <animate attributeName="stop-color" values="#054f16; #91bc9c" dur="3s" fill="freeze" /> </stop> <stop offset="100%" stop-color="#91bc9c"> <animate attributeName="stop-color" values="#91bc9c; #054f16" dur="3s" fill="freeze" /> </stop> </linearGradient> </defs>
<animate> element resides within the 100% stop point for each gradient and targets the stop-color. The color values are animated through the values attribute, over a period of 3 seconds, and the animation is set to stop, or “freeze” once it completes one cycle.
Demo 3: Sky
The concept of a sunset is an ideal example of when animating a stop’s offset would be needed. There are two gradients here, each having a series of animated color changes. With an additional animation on the offset of the 100% stop point the point moves down (to 0) and then back up again.
<defs> <linearGradient id="skyGradient" x1="100%" y1="100%"> <stop offset="0%" stop-color="lightblue" stop-opacity=".5"> <animate attributeName="stop-color" values="lightblue;blue;red;red;black;red;red;purple;lightblue" dur="14s" repeatCount="indefinite" /> </stop> <stop offset="100%" stop-color="lightblue" stop-opacity=".5"> <animate attributeName="stop-color" values="lightblue;orange;purple;purple;black;purple;purple;blue;lightblue" dur="14s" repeatCount="indefinite" /> <animate attributeName="offset" values=".95;.80;.60;.40;.20;0;.20;.40;.60;.80;.95" dur="14s" repeatCount="indefinite" /> </stop> </linearGradient> </defs>
For the stop-color animations there’s a list of color values the gradient will cycle through within 14s. The additional offset animation changes the location of the 100% stop point through a series of numerical values, also within 14s.
It is important to mention here that while you should technically be able to use percentages when animating offset, and can do so without problems in Firefox, Chrome and Safari will not render the animation on the offset when percentage values are used within
<animate>. The work around here is to simply avoid using percentages, as shown in the code above.
For this article we discussed the basic structure of SVG gradients, how to utilize SVG SMIL animation once they are created, and reviewed some demos regarding how this can be handy in communicating to users.
Hopefully all this inspires you to take a look at writing gradients within SVG code and get them moving all within the same SVG element.