There are three ways to fill or stroke SVG elements. You can use a solid color, a pattern, or a gradient. So far in this series we’ve seen the first two. Now it’s time to talk about the third, gradients.
SVG provides for both linear and radial gradients. I’ll cover linear gradients today and take a look at radial gradients next week.
SVG Linear Gradients
If you’ve followed this series you’ll recognize a lot of familiar aspects to gradients. You define them inside
<defs> and reference them for later reuse as a fill or stroke.
You define a linear gradient with the
<linearGradient> element. Let’s start with an example of a simple gradient that transitions from blue to green.
Aside: Is it just me or did the creators of SVG do a good very job naming SVG elements and attributes?
1 2 3 4 5 6 7 8 9 10
<svg width="660" height="220"> <defs> <linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" stop-color="#05a"/> <stop offset="100%" stop-color="#0a5"/> </linearGradient> </defs> <rect x="10" y="10" width="600" height="200" fill="url(#linear)" /> </svg>
The example defines a linear gradient inside
<defs> tags and gives the gradient and id of linear. The id is then referenced by the rectangles’s fill property. We’ve seen this before with patterns, symbols, and groups. You define your graphic in one place and reference it in another.
Let’s turn our attention to what’s new. Have a look at the
<linearGradient> element and it’s four attributes. The x and y values determine the starting and ending points of the gradient. In this case the gradient will start at 0% and end at 100% in the x direction and it remains at 0% in the y direction. In other words this will be a horizontal linear gradient.
While I chose to use percents, both x and y values can be either a percent or a number between 0.0 and 1.0. If no value is specified 0 or 0% is the default.
<linearGradient> tags are two color stops defined by
<stop> elements. The first color stop sets a blue color at an offset of 0% and the second sets a green color at an offset of 100%.
Here’s the resulting graphic.
I assume the result is what you expected or close to it. The first color stop (blue) is the color at the left edge (0%), the second color stop (green) is the color at the right edge (100%), and in between is a transition from one to the other.
Here’s the result when I change the x2 value to 50%. You can see the fill is entirely green at 50% of the way across the rectangle and remains green from 50% to 100%. The transition occurs between 0% and 50%.
The gradient can be added to a stroke as well as a fill. Here I changed the rectangle from the previous example (with x2 set at 50%). I set the fill of the rectangle to a solid color and added the gradient to the stroke. A stroke-width of 20 should be more than enough to see the gradient.
<rect x="10" y="10" width="600" height="200" stroke="url(#linear)" stroke-width="20" fill="#630" />
Here’s the result.
You can see the gradient is now added to the stroke instead of the fill and hopefully I made the stroke wide enough so you can see that the gradient transitions between 0% and 50%, the same as in the previous example.
You aren’t limited to start and end color stops. You can define as many as you want. Here I added a third color stop so the gradient passes through red in between the blue and green.
1 2 3 4 5 6 7 8 9 10 11
<svg width="660" height="220"> <defs> <linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" stop-color="#05a"/> <stop offset="50%" stop-color="#a55"/> <stop offset="100%" stop-color="#0a5"/> </linearGradient> </defs> <rect x="10" y="10" width="600" height="200" fill="url(#linear)" /> </svg>
The resulting graphic shows blue at 0%, red at 50%, and green at 100%, with transitions in between.
Those are the very basics of linear gradients and hopefully you agree they’re easy to work with. However, there’s more we can do with them.
Attributes of the
I showed some of the attributes on both the
<stop> elements, but there are more. Let’s start with
<stop>, because I get to make that silly pun about starting with a stop and also because there’s only one attribute for it we haven’t yet seen.
<stop> element accepts three attributes, offset, stop-color, and stop-opacity. We’ve seen the first two already, but here they all are defined.
- offset — For linear gradients offset represents a location along the gradient vector. It defines where the gradient stop is located. You can set it as a number between 0 and 1 or a percent from 0% to 100%.
- stop-color — defines the color at the offset.
- stop-opacity — defines the opacity of the stop color at its offset as a number between 0 and 1 or as a percent between 0% and 100%.
So far I haven’t used the stop-opacity attribute, though I expect you already know how to use it. The default value is 1.0 and since I haven’t set it in any of the examples, we’ve seen a fully opaque color at each color stop.
Here’s an example where I set the first color stop to show at 50% opacity (0.5) and the second I kept at 100% (1.0).
1 2 3 4 5 6 7 8 9 10
<svg width="660" height="220"> <defs> <linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" stop-color="#05a" stop-opacity="0.5" /> <stop offset="100%" stop-color="#0a5" stop-opacity="1.0" /> </linearGradient> </defs> <rect x="10" y="10" width="600" height="200" fill="url(#linear)" /> </svg>
Here’s the result, which I again assume was at least similar to what you expected.
Attributes of the
There’s more than one attribute left to show you on
<linearGradients>, however, if you’ve been following along with the series, most will be familiar.
- x1, x2, y1, y2 — define starting and stopping points for the gradient. The 1s are start points and the 2s are end points.
- id — the hook to reference the gradient.
- xlink:href — a way to reference one gradient inside another. The attributes on the referenced gradient are inherited, but can be overwritten.
Here’s an example showing one gradient referencing another, inheriting its values, and then overwriting a couple of them.
1 2 3 4 5 6 7 8 9 10 11
<svg width="660" height="220"> <linearGradient id="gradient1"> <stop id="stop1" offset="0%" stop-color="#05a" stop-opacity="0.5" /> <stop id="stop2" offset="100%" stop-color="#0a5"/> </linearGradient> <linearGradient id="gradient2" x1="0" x2="0" y1="0" y2="1" xlink:href="#gradient1"/> <rect x="0" y="0" width="600" height="200" fill="url(#gradient2)" /> </svg>
The first gradient is from the previous example. The second gradient references it and changes the direction to vertical by setting new values for x2 and y2.
You can see in the resulting graphic that the gradient is the same blue to green transition, but now it runs vertically instead of horizontally.
The next two attributes are new, but again they should look familiar. Markers had markerUnits and patterns had patternUnits to allow the marker or pattern to scale or not to scale. Guess what attribute gradients have and guess what it does.
The gradientUnits attribute takes two familiar values, userSpaceOnUse and objectBoundingBox, which determine whether the gradient scales with the element that references it or not. It determines the scale of x1, y1, x2, y2.
- userSpaceOnUse — x1, y1, x2, y2 represent coordinates in the current user coordinate system. In other words the values in the gradient are absolute values.
- objectBoundingBox — x1, y1, x2, y2 represent coordinates in a system established by the bounding box of the element to which the gradient is applied. In other words the gradient scales with the element it’s applied to.
The elements we’ve encountered through this series can be transformed and gradients are no different. The gradientTransform attribute allows you to add transforms like rotate() and transition() to any gradient.
Here I added a gradientTransform to the second gradient from the previous example and rotated it –50 degrees.
<linearGradient id="gradient2" x1="0" y1="0" x2="0" y2="1" xlink:href="#gradient1" gradientTransform="rotate(-50)" />
The rotation is harder to see with gradients than with patterns, but hopefully you can tell the gradient here as been rotated. If not, compare it to the previous result and you should see the difference.
That brings us to the last of the
<linearGradient> attributes, spreadMethod, which is entirely new. The spreadMethod attributes takes one of three values pad, reflect, or repeat. It defines how the gradient is spread out over the element when the start and end color stops are inside the shape instead of at 0% and 100%.
- pad — (default) uses the start and stop colors of the gradient to fill the remainder of the region. For example, if the first stop is at 20%, the region from 0% to 20% will be filled with the same color.
- reflect — reflects the gradient pattern from start-to-end then end-to-start then start-to-end, continuously until the region is filled.
- repeat — repeats the gradient pattern from start-to-end continuously until the region is filled.
All three are easier to understand with an example. Here’s an example of a horizontal gradient with the spreadMethod attribute added. Since the color stops need to be inside the rectangle before spreadMethod has any effect, I changed the value of x1 to 40% and the value of x2 to 60%.
1 2 3 4 5 6 7 8 9 10
<svg width="660" height="220"> <defs> <linearGradient id="linear" x1="40%" y1="0%" x2="60%" y2="0%" spreadMethod="pad"> <stop offset="0%" stop-color="#05a"/> <stop offset="100%" stop-color="#0a5"/> </linearGradient> </defs> <rect x="10" y="10" width="600" height="200" fill="url(#linear)" /> </svg>
This first result uses a spreadMethod of pad and it looks similar to the original example with color stops at 0% and 100%. There’s a little more full color and a little less transition in the middle, but otherwise it’s similar.
Note: Unfortunately there are browser issues with the reflect and repeat values of spreadMethod. Neither works in Safari, though they should work in other browsers. I’m including screenshots of the results (from Firefox) so you can see what the results should look like even if the code doesn’t work in your browser.
Here’s the same gradient with the spreadMethod set to reflect. The gradient transitions back and forth between blue and green. At 40% the color is the blue set on the first color stop and at 60% it’s the green set on the second color stop.
The reflection leads to a gradient transition back and forth between the two color stops. It almost looks like it comes into focus at the point where a solid color is displayed and falls out of focus somewhere in the transition.
Here’s the gradient one more time with the spreadMethod set to repeat. It starts the same way by transitioning from blue to green, but at the exact point where it previously reversed itself and transitioned back to blue, it now abruptly changes to blue and transitions back to green.
The pattern then continues with another abrupt change to blue and transition to green and it continues until 100% of the rectangle is filled. If you compare this example to the previous one, you’ll notice the fill is still entirely blue and green at the color stops of 40% and 60% respectively.
Like patterns, markers, and symbols, gradients are defined in one location and then referenced and used as the fill or stroke on another SVG element.
<linearGradient> you include color stops with the
<stop> element and attributes on both the gradient and the color stops provide options for you to get creative with your linear gradients.
Using the xlink:href attribute you can have one gradient inherit from another, making it easy, for example, to define color stops on one gradient and change the direction of the transition on another.
SVG allows for radial gradients as well as linear gradients and that’s where I’ll pick things up next week. If you understand how to work with linear gradients, radial gradients should be pretty easy to understand and work with as well.
Download a free sample from my book, Design Fundamentals.