SVG Basics—Fills And Strokes

The last couple of weeks I’ve been walking through some of the basics of scalable vector graphics. First I showed how to include SVG in HTML and then I showed how to create the basic shapes SVG provides.

In both posts I used the fill and stroke properties in order to see the what we were creating. Today I want to talk in more detail about fills and strokes and the properties associated with each.

Fill Properties

As you probably expect, the fill property takes a color and fills the interior of the shape (or line) you created with that color. Here it is added to a rectangle and circle

1
2
<rect class="rectangle" width="100%" height="100%" fill="red" />
<circle class="circle" cx="150" cy="150" r="100" fill="#039" />

You could also set the values of fill in your CSS. Below I set the fill on different classes, but you could set it on the SVG property directly too if you prefer.

1
2
.rectangle {fill: red;}
.circle {fill: #039;}

By default fill will be black or #000000 so if you don’t want a shape to be filled with color you need to explicitly set it to none.

1
<rect class="rectangle" width="100%" height="100%" fill="none" />

What’s considered inside the shape (or line) depends on the fill-rule property which can have the values nonzero or evenodd.

1
2
fill-rule="nonzero"
fill-rule="evenodd"

I’m not even going to pretend I completely follow how the two algorithms work. Here are the definitions from the spec. Below each is an example image of each algorithm, also from the spec.

nonzero—This rule determines the “insideness” of a point on the canvas by drawing a ray from that point to infinity in any direction and then examining the places where a segment of the shape crosses the ray. Starting with a count of zero, add one each time a path segment crosses the ray from left to right and subtract one each time a path segment crosses the ray from right to left. After counting the crossings, if the result is zero then the point is outside the path. Otherwise, it is inside.

fill rule non-zero

evenodd—This rule determines the “insideness” of a point on the canvas by drawing a ray from that point to infinity in any direction and counting the number of path segments from the given shape that the ray crosses. If this number is odd, the point is inside; if even, the point is outside.

fill rule even odd

What I find confusing is the last example in each of the SVGs. I’m not following why they look the same, when the second examples look different. If anyone knows, I’d appreciate knowing too.

You can also set the fill-opacity of any fill.

1
fill-opacity="0.5"

It takes a value between 0 (transparent) and 1 (opaque) and works just like the CSS opacity property and I’m guessing no further explanation is necessary.

Stroke Properties

You use fill properties to add color inside the element. Stroke properties add color around the element. They define the outline or contour of an element.

There are a few more stroke properties than fill properties, and quite honestly I find them a bit more interesting. If you read the previous posts in this series, you will have seen two already, stroke and stroke-width. The first takes a color as a value and the second takes a unit of measurement as a value.

1
2
3
4
5
6
stroke="blue"
stroke="#347559

stroke-width="3px"
stroke-width="1em"
stroke-width="2%"

When a percentage is used for the stroke-width value, it’s a percentage of the current viewport.

1
2
3
<svg width="300px" height="150px">
  <ellipse cx="150" cy="75" rx="100" ry="75" fill="none" stroke="blue" stroke-width="3px" />
</svg>

There’s also a stroke-opacity property, which I again hope is self-explanatory.

1
stroke-opacity="0.25"

It doesn’t end there. The stroke-linecap property gives you some control over the shape at the ends of lines. Your choices are butt, square, and round. You can see an example of each in the image below.

title

The stroke-linejoin property is similar but controls the joints between line segments. You might set it when working with a polyline. It also takes three values, miter, round, and bevel, which you can see in the image below.

title

If you set miter as the linejoin value and it the lines meet at a sharp angle, it’s possible for the miter to extend beyond the thickness of the stroke.

The stroke-miterlimit property sets a limit on the ratio between miter-length and stroke-width. It expects a number greater than or equal to 1. When the limit is exceeded the stroke is converted to a bevel.

Dashed lines are possible with the stroke-dasharray property. It allows you to set both the length of each dash and the space between dashes.

1
2
3
4
5
6
<svg width="600px" height="300px">
  <line x1="0" y1="20" x2="600" y2="20" stroke="#000" stroke-width="3" stroke-dasharray="10 2" />
  <line x1="0" y1="40" x2="600" y2="40" stroke="#000" stroke-width="3" stroke-dasharray="5 10" />
  <line x1="0" y1="60" x2="600" y2="60" stroke="#000" stroke-width="3" stroke-dasharray="1 1" />
  <line x1="0" y1="80" x2="600" y2="80" stroke="#000" stroke-width="3" stroke-dasharray="10" />
</svg>

The first value is the length of the dash and the second value is the space between each dash. If you only supply a single value (the last example above), it will be used twice resulting in equal dash length and space between dashes.

The stroke-dasharray can do more. Even though I’ve shown it taking a single set of values, it can accept a comma separated list of value pairs.

1
2
3
<svg width="600px" height="60px">
    <line x1="0" y1="20" x2="600" y2="20" stroke="#000" stroke-width="3" stroke-dasharray="10 4, 5 10, 1 1, 10 30" />
</svg>

The dash will follow the pattern set by the different pairs of line length and space and then it will repeat until it runs out room to display. In the example above, I set the last space to 30 to make it easier to see the pattern repeating.

One last property is stroke-dashoffset, which allows you set the distance into the dash pattern to start the dash. Acceptable values are any unit of measurement and again if a percent is used, it’s a percent of the viewport.

1
2
3
<svg width="600px" height="60px">
    <line x1="0" y1="20" x2="600" y2="20" stroke="#000" stroke-width="3" stroke-dasharray="10 4, 5 10, 1 1, 10 30" stroke-dashoffset="10" />
</svg>

Read the previous paragraph again. The stroke-dashoffset property works opposite to my initial expectation. My instinct was to think setting the offset would delay the start of the pattern by the amount set in the offset. What happens is the reverse. The offset is how far into the pattern to start it.

Here’s an example of the same pattern with and without an offset applied. Hopefully the visually makes it clear what’s going on.

Shapes and Lines

At the start of this post I mentioned you could fill both a shape and a line, which may have sounded a little strange. How would you fill a line, after all? It depends on the line.

Other than the possibly confusing nonzero and evenodd algorithms, you probably don’t need my help to understand what gets filled and what gets stroked on a basic shape like a rectangle or circle. The stroke is the shape’s outline and the fill is everything inside that outline.

What about lines, though? Most lines won’t take any fill. What you see is the line’s stroke. There’s nothing inside to fill. However, when the line is a polyline if can be filled. The polyline be treated as though it were a polygon with the exact same points for each line segment.

For example both the polyline and polygon below will look exactly the same.

1
2
3
4
5
6
7
<svg width="300px" height="200px">
  <polyline points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" />
</svg>

<svg width="300px" height="200px">
  <polygon points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" />
</svg>

If you add a stroke, however, you can see the polygon completes the shape with a line directly from end point to start point, where the polyline doesn’t show the line. The fills are the same though.

1
2
3
4
5
6
<svg width="300px" height="200px">
  <polyline points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" stroke="#000" stroke-width="5" />
</svg>
<svg width="300px" height="200px">
  <polygon points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" stroke="#000" stroke-width="5" />
</svg>

SVG Properties and CSS

For most of the examples in this series. I’ve been setting SVG properties as attributes on different SVG elements. Earlier in this post I showed how you could set values on fill in your CSS file. You can set more SVG properties in CSS. Not all, but you can set both fills and strokes in CSS.

You can add the CSS inline as below.

1
2
3
<svg width="300px" height="300px">
    <rect x="20" y="20" width="250px" height="125px" style="fill: teal; stroke: 5px;" />
</svg>

You can also set styles directly in your CSS file.

1
2
3
<svg width="300px" height="300px">
  <rect class="example" x="20" y="20" width="250px" height="125px" />
</svg>
1
2
3
4
5
.example {
  fill: teal;
  stroke: red;
  stroke-width: 5px
}

Just remember to set fill as opposed to background color and set stroke and stroke-width, instead of border-color and border-width.

Plenty of other SVG properties can be written as CSS properties instead of having to add them as attributes on an SVG element. The W3C maintains a table that lists all the different SVG properties that can be styled in CSS.

Closing Thoughts

As I hope you can see, adding fills and strokes to basic shapes and lines is rather easy. If you’ve worked with background-colors and borders in CSS, much of what’s here probably seemed like review.

I find the fill-rule algorithms a bit confusing, but it will always be easy enough to test the two possibilities and see which one gives you what you want.

The opacity of both fill and stroke can be set and stroke also provides properties for the shape of the line at the end points or where line segments join. You can also turn solid strokes into dashed strokes.

You now have enough information to create simple SVGs. You know how to create, fill, and stroke simple shapes like rectangles and circles or build up more complex shapes with polygons. You can do similar with simple and complex lines.

Still it’s all rather basic. There’s a lot more you can do with SVG than fill circles and rectangles with with color. For example, instead of a solid fill you can fill shapes with gradients or patterns made up of other SVG elements.

Before we get there though, I want to look at something I mentioned when talking about shapes. I mentioned paths as another way to create them. The next couple of weeks I’ll look at how to create lines, curves, and shapes, using paths.

Download a free sample from my book, Design Fundamentals.

Leave a Reply

Your email address will not be published. Required fields are marked *