Gradients in SVG
As well as allowing a greater choice of solid colors, SVG provides elements to allow us to create color gradients. A gradient is a change in color value along a line. For example, a rectangle could be blue at one side and gradually change to pale gray on the other side. In SVG terminology, that is a linear gradient.
In SVG, gradients may be applied to either the stroke or fill of an SVG shape, or both if you prefer. SVG provides two elements, the linearGradient element and the radialGradient element, that, respectively describe linear and radial gradients.
Linear Gradients
A gradient is typically defined using the relevant SVG gradient element nested within a defs element, where all definitions that are to be used elsewhere in an SVG document are located. The relevant element in the definition section is then referenced using a "bare names" form of XPointer as the value of the relevant property of the graphic shape. For example, to define and use a simple linear gradient for a line, we could use code like that shown in Listing 3.16.
Listing 3.16 SimpleLinearGradient.svgAn SVG Linear Gradient
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="" height=""> <defs> <linearGradient id="FirstGradient" > <stop offset="0%" style="stop-color:#FF00FF"/> <stop offset="100%" style="stop-color:#FFFF00"/> </linearGradient> </defs> <line x1="50" y1="70" x2="250" y2="70" style="stroke:url(#FirstGradient); stroke-width:6"/> </svg>
The visual appearance produced is a line that is magenta in color at the left, gradually changing to yellow at the right end of the line. To see the gradient best, you need to run the code onscreen, but Figure 3.12 may give you some indication of the visual appearance.
Figure 3.12 A horizontal SVG linear gradient.
Notice that the linear gradient is defined in a linearGradient element nested within the defs element of the SVG document:
<defs> <linearGradient id="FirstGradient" > <stop offset="0%" style="stop-color:#FF00FF"/> <stop offset="100%" style="stop-color:#FFFF00"/> </linearGradient> </defs>
This code snippet defines only a horizontal linear gradient from magenta on the left to yellow on the right. If it is not referenced elsewhere in the SVG document by an SVG element that is to be rendered, the presence of the gradient within the definitions of the document has no effect on the visual appearance produced by the SVG rendering engine. Thus, the code
<line x1="50" y1="70" x2="250" y2="70" style="stroke:url(#FirstGradient); stroke-width:6"/>
which references the gradient, is essential to produce a visual effect from the gradient onscreen.
Linear gradients in SVG may be horizontal, vertical, or may be applied diagonally. The default behavior is to produce a horizontal gradient. A linear gradient may have two stop colors, as shown in the earlier example, or may have several, thus producing a number of color transitions within a single graphic.
Let's look at a number of the options for using a linear gradient in SVG. First, let's look at how to apply simple horizontal gradients to the stroke and/or fill of SVG shapes.
Listing 3.17 illustrates the use of three gradients to control the appearance of a linear gradient in the stroke of three SVG line elements.
Listing 3.17 StrokeGradients.svgLinear Gradients in line Elements
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="400" height="500"> <defs> <linearGradient id="Gradient1" > <stop offset="0%" style="stop-color:#FF0000"/> <stop offset="100%" style="stop-color:#00FF00"/> </linearGradient> <linearGradient id="Gradient2" > <stop offset="0%" style="stop-color:#0000FF"/> <stop offset="100%" style="stop-color:#FFFFFF"/> </linearGradient> <linearGradient id="Gradient3" > <stop offset="0%" style="stop-color:#FFFF00"/> <stop offset="100%" style="stop-color:#0000FF"/> </linearGradient> </defs> <line x1="20" y1="20" x2="220" y2="20" style="stroke:url(#Gradient1); stroke-width:4"/> <line x1="20" y1="40" x2="220" y2="40" style="stroke:url(#Gradient2); stroke-width:4"/> <line x1="20" y1="60" x2="220" y2="60" style="stroke:url(#Gradient3); stroke-width:4"/> </svg>
As you can see in Figure 3.13, which is zoomed and panned, we again have three lines. If you download and run the code, you will see that each of the three lines has a simple linear gradient, but the color values for each gradient are distinct. The first line has a gradient from red at the left to green at the right. The second line has a gradient from blue at the left to white at the right, and the third line has a linear gradient from yellow at the left to blue at the right.
Figure 3.13 Three linear gradients on line elements.
We can apply similar gradients to the fill of shapes. For example, we can create simple linear gradients in the fill of SVG rect elements, as well as in the fill of other graphic shapes. Listing 3.18 shows how simple linear gradients can be applied to rectangular shapes, such as those you might use in a bar chart.
Listing 3.18 FillGradients.svgApplying a Linear Gradient to the Fill of a Shape
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="400" height="500"> <defs> <linearGradient id="Gradient1" > <stop offset="0%" style="stop-color:#FF0000"/> <stop offset="100%" style="stop-color:#00FF00"/> </linearGradient> <linearGradient id="Gradient2" > <stop offset="0%" style="stop-color:#0000FF"/> <stop offset="100%" style="stop-color:#FFFFFF"/> </linearGradient> <linearGradient id="Gradient3" > <stop offset="0%" style="stop-color:#FFFF00"/> <stop offset="100%" style="stop-color:#0000FF"/> </linearGradient> </defs> <rect x="40" y="25" width="300" height="75" style="stroke:red; fill:url(#Gradient1)"/> <rect x="40" y="175" width="300" height="75" style="stroke:red; fill:url(#Gradient2)"/> <rect x="40" y="325" width="300" height="75" style="stroke:red; fill:url(#Gradient3)"/> </svg>
Each rectangle has a red stroke. The fill of each rectangle is defined in the linearGradient elements, which are then referenced by the fill property of the style attribute of each rect element. For example, we apply the previously defined linear gradient to the fill of the top rectangle using the following code:
style="stroke:red; fill:url(#Gradient1)"
Up to this point, we have relied on the default behavior of the SVG rendering engine to produce a horizontal linear gradient. We can make that explicit by adding x1, y1, x2, and y2 attributes to the linearGradient element nested within the defs element. Listing 3.19 shows how this is done.
Listing 3.19 ExplicitHorizGradients.svgCreating Horizontal Gradients Explicitly
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="400" height="500"> <defs> <linearGradient x1="0%" y1="0%" x2="100%" y2="0%" id="Gradient1" > <stop offset="0%" style="stop-color:#FF0000"/> <stop offset="100%" style="stop-color:#00FF00"/> </linearGradient> <linearGradient x1="0%" y1="0%" x2="100%" y2="0%" id="Gradient2" > <stop offset="0%" style="stop-color:#0000FF"/> <stop offset="100%" style="stop-color:#FFFFFF"/> </linearGradient> <linearGradient x1="0%" y1="0%" x2="100%" y2="0%" id="Gradient3" > <stop offset="0%" style="stop-color:#FFFF00"/> <stop offset="100%" style="stop-color:#0000FF"/> </linearGradient> </defs> <rect x="40" y="25" width="300" height="75" style="stroke:red; fill:url(#Gradient1)"/> <rect x="40" y="175" width="300" height="75" style="stroke:red; fill:url(#Gradient2)"/> <rect x="40" y="325" width="300" height="75" style="stroke:red; fill:url(#Gradient3)"/> </svg>
Notice that the values of the x1 and x2 attributes of each linearGradient element differ, indicating that the gradient changes on a horizontal axis, that is, as we move from the x1 to x2 positions. The visual appearance is as before.
We can produce a vertical gradient in each rectangle by making the values of the x1 and x2 attributes the same, indicating no change in the gradient along a horizontal axis, and by introducing a difference in the values of the y1 and y2 attributes, indicating that there is a change in the appearance of the gradient along the y axis; that is, it is a vertical gradient. Listing 3.20 shows how to do this.
Listing 3.20 ExplicitVertGradients.svgCreating Vertical Gradients in SVG
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="400" height="500"> <defs> <linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="Gradient1" > <stop offset="0%" style="stop-color:#FF0000"/> <stop offset="100%" style="stop-color:#00FF00"/> </linearGradient> <linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="Gradient2" > <stop offset="0%" style="stop-color:#0000FF"/> <stop offset="100%" style="stop-color:#FFFFFF"/> </linearGradient> <linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="Gradient3" > <stop offset="0%" style="stop-color:#FFFF00"/> <stop offset="100%" style="stop-color:#0000FF"/> </linearGradient> </defs> <rect x="40" y="25" width="300" height="75" style="stroke:red; fill:url(#Gradient1)"/> <rect x="40" y="175" width="300" height="75" style="stroke:red; fill:url(#Gradient2)"/> <rect x="40" y="325" width="300" height="75" style="stroke:red; fill:url(#Gradient3)"/> </svg>
You have seen how we can explicitly produce a horizontal gradient by specifying differing values for the x1 and x2 attributes of the linearGradient element and how we can produce a vertical gradient by using different values for the y1 and y2 attributes. To produce a diagonal gradient, we simply ensure that both attribute pairsthe x1 and x2 and y1 and y2 attributeshave different values. Listing 3.21 shows this in practice.
Listing 3.21 SimpleDiagonalGradient.svgA Diagonal Linear Gradient
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="400" height="500"> <defs> <linearGradient x1="0%" y1="0%" x2="100%" y2="100%" id="Gradient2" > <stop offset="0%" style="stop-color:#0000FF"/> <stop offset="100%" style="stop-color:#FF0000"/> </linearGradient> </defs> <rect x="40" y="25" width="300" height="300" style="stroke:red; fill:url(#Gradient2)"/> </svg>
Onscreen you will see a square that is blue in the top-left corner, shading through various shades of purple down and to the right, finishing with red in the bottom-right corner.
As well as specifying a stop-color property for each stop element, you may also specify a stop-opacity property, thus allowing partially transparent gradients to be created.
Radial Gradients
Producing a radial gradient rather than a linear gradient requires a syntax that is very similar to that for a linear gradient. The radialGradient element is nested within a defs element and has an id attribute that is then referenced as the fill or stroke property of an SVG graphic shape. The syntax of the radialGradient element differs slightly, as you can see in Listing 3.22.
Listing 3.22 SimpleRadialGradient.svgCreating a Simple Radial Gradient in SVG
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="400" height="400"> <defs> <radialGradient id="FirstRadialGradient" gradientUnits="userSpaceOnUse" cx="200" cy="200" r="150" fx="200" fy="200"> <stop offset="0%" style="stop-color:#FF00FF"/> <stop offset="25%" style="stop-color:#00FF00"/> <stop offset="50%" style="stop-color:#FFFF00"/> <stop offset="75%" style="stop-color:#0000FF"/> <stop offset="100%" style="stop-color:#FFFF00"/> </radialGradient> </defs> <rect x="0" y="0" width="400" height="400" style="fill:url(#FirstRadialGradient);"/> </svg>
The cx and cy attributes on the radialGradient element define the center position of the gradient. The r attribute defines the radius over which the radius applies. The fx and fy attributes define the focal point for the gradient.
The visual appearance produced onscreen is pretty strident but does give you some indication of the types of visual effects that can be produced using radial gradients. Figure 3.14 shows the onscreen appearance when Listing 3.22 is run.
Figure 3.14 A vibrant radial gradient.
Radial gradients on a much smaller scale can, when combined with declarative animation elements, be used to create visually unmissable markers for important content. Be careful, however, not to overdo the effect, or you may simply irritate the users.