Vector URL images

Among the many options you have to include SVG in a document you gain the most flexibility adding the syntax inline.

<svg viewBox="-6 -6.125 12 12">
	<!-- ...path, rect & circle -->
</svg>

In this manner you are able to consider the element and each nested node individually. And theoretically, you can change the appearance of each unit directly with CSS. But with CSS itself you are also able to add vector graphics through the url() function. There are a few shortcomings, but also practical use cases, so that you can lean on the feature to style a page in several ways.

url

There are multiple properties supporting the url syntax — we’ll explore a handful in a moment — but they all share a similar structure.

url('shapes.svg')

In between parenthesis the function tends to describe a url, in which instance the browser looks for the resource at the proper location.

You can include SVG as any other asset pointing to the file, but if you stick with vector graphics you have one more option. Technically, one formula to inject the syntax right in the stylesheet.

url('data:image/svg+xml,<svg viewBox="-6 -6.125 12 12"><!-- ... --></svg>')

The string introduces a data URL and must include the type of SVG before the actual markup.

That being said, once you introduce the <svg> element you have free reign over the contents. You can add whichever element and attribute, and be sure to find the crisp result with a few precautions.

Immediately, you need to add the xmlns attribute, pointing to the vector standard.

url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6.125 12 12"><!-- ... --></svg>')

In an HTML document the pairing is superfluous, but as you add the resource as a separate entity you cannot escape the value.

Past the mandatory instruction, you may need to update the markup in smaller ways. If you care to add the syntax on multiple lines — it might be confusing to have the sequence in a cumbersome horizontal rule — you can do so by adding a backslash character at the end of each row.

url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6.125 12 12">\\
	<!-- ...path, rect & circle -->\\
</svg>')

If you care about certain colors then, you must be wary of escaping special characters, like the hash character for every hexadecimal combination.

url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6.125 12 12">\\
	<path fill="%23ff000" />\\
</svg>')

For better or worse, you need to substitute the pound with %23.

There aren’t many characters which must be corrected, so that at the end of the day you can rely on mostly the same code you’d have in the markup. If something doesn’t look quite right, or if a vector doesn’t show up at all, you then have a way of fixing the issue by exploring the list of reserved characters and escape patterns.

background-image

Possibly the most straightforward property in terms of meaning, background-image lets you style the background of an element with a color, gradient, or again a full-blown image. With the url function and the string shown earlier, you can add a vector graphic after the specific property.

div {
	inline-size: 10rem;
	block-size: 10rem;
	background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6.125 12 12">\<!-- path, rect & circle -->\</svg>');
}

The image is sized relative to the container, unless you specify a different measure in the width and height attribute.

But you have more control with other background related properties, changing the size, position and even how the image should possibly repeat.

div {
	/* ... */
	background-position: 50%;
	background-size: 50%;
	background-repeat: no-repeat;
}

And as prefaced, there are a few drawbacks relative to inline SVG. The vector is included as an image, so that you lose the fine-grain control on the composing elements. And even values like currentColor won’t work in the same flexible manner.

div {
	background-image: url('data:image/svg+xml,<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6.125 12 12"><!-- ... --></svg>');
}

The mention won’t change the fact the color is fixed, and it cannot change from outside. Or at least, not in the usual manner. In CSS you can still rely on the different properties changing the style of HTML elements. Consider for instance three shapes, drawn with the named colors “red”, “lime” and “blue” — if you are curious why I did not pick green, there is a reason in a past article dissecting the values.

You may not change the values with the color property, but you can do so with a filter instead.

div {
	filter: invert(100%);
}

Inverting the colors you explore the full spectrum to have shades of “cyan”, “magenta” and “yellow”.

red lime blue
cyan magenta yellow

mask-image

If you want to paint the graphic with CSS and a given color, perhaps you still aspire to rely on currentColor, there is a way with another CSS property. Or rather two, to support most modern browsers.

mask-image, and the not-so-distant, WebKit version, works to carve out an element with the input graphic. Such input can be a vector graphic, included in the same exact manner as the background image.

With this in mind, you can work around the currentColor conundrum rather explicitly. First paint the area with a given background.

div {
	background: currentColor;
}

You could use any color and repeating background-image you could even introduce a gradient.

Following the painting operation, mask the result with the url function.

.mask-image {
	background: currentColor;
	-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-23.204545974731445 -24.920761108398438 45.409088134765625 45.409088134765625"><!-- star-shaped path --></svg>');
	mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-23.204545974731445 -24.920761108398438 45.409088134765625 45.409088134765625"><!-- star-shaped path --></svg>');
}

As you size, position and alter the background you can change the default behavior of the mask with mask related properties. But making sure you repeat the instructions with the -webkit- prefix, the code works to reintroduce the vector with the chosen look.

background-image
mask-image

list-image

The list of properties supporting the url function includes lists elements as well, be it ordered or unordered. But as an example, I’ll describe the simpler <ul>.

One clear way you have to tweak the design is to change the marker before each list item. And in the context of a vector graphic, you do so with the list-image property.

ul {
	list-style-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-23.204545974731445 -24.920761108398438 45.409088134765625 45.409088134765625"><!-- star-shaped path --></svg>');
}

The syntax should be now familiar, but also the result and the drawbacks. As with background-image, the asset is static and the marker has a fixed color. But as with the background, you can work around the problem with a mask.

list-image
mask-image

A mask and a few asterisks. The solution is far from perfect, but consider it another option in terms of design.

Instead of changing the marker with the list-image property remove the default bullet point.

.mask-image {
	list-style: none;
}

The idea is to then reintroduce the milestone with the ::before pseudo element.

ul li::before {
	content: '';
	display: inline-block;
	background: currentColor;
	inline-size: 0.5em;
	block-size: 0.5em;
	margin-inline-end: 0.5rem;
}

There are a few properties for the selector, some of which worth a special mention. content is essential to show the decorative element, as well as the display set to inline-block. With the two the square appears before each item in the list. background, then, colors the marker, and prompts the same setup of the background code.

The rest is a matter of tweaking. The inline and block size are picked with a bit of a guess, looking at the dimensions some browsers choose for the default markers.

The margin, separating the graphic from the associated text, has a similar function, placing the point at a safe distance. The result is far from the same, but means the pseudo element is displayed with a solid square. A square you can finally mask with the url function and the same SVG.

ul li::before {
	/* ... */
	-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-23.204545974731445 -24.920761108398438 45.409088134765625 45.409088134765625"><!-- star-shaped path --></svg>');
	mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-23.204545974731445 -24.920761108398438 45.409088134765625 45.409088134765625"><!-- star-shaped path --></svg>');
}

You can spot plenty of differences comparing the two versions, but you might agree that each has its own reason. What is more, you have a few ways to design with more flair.