SVG is a lightweight vector image format that’s used to display a variety of graphics on the Web and other environments with support for interactivity and animation. In this article, we’ll explore the various ways to use CSS with SVG, and ways to include SVGs in a web page and manipulate them.
The Scalable Vector Graphic (SVG) format has been an open standard since 1999, but browser usage became practical in 2011 following the release of Internet Explorer 9. Today, SVG is well supported across all browsers, although more advanced features can vary.
Key Takeaways
- SVGs offer scalability and quality preservation at any size, making them ideal for graphics like logos and icons that require resizing without loss of detail.
- CSS can be used to style and manipulate SVG elements directly in the DOM, allowing for dynamic interactions and styling that can be applied consistently across multiple SVGs.
- SVG sprites consolidate multiple images into a single file, enhancing performance by reducing HTTP requests, with added benefits of caching and using CSS to manage visual aspects.
- Advanced SVG usage includes animations and interactivity within standalone files, demonstrating the format’s versatility for both simple and sophisticated web graphics applications.
SVG Benefits
Bitmap image formats such as WebP, PNG, JPG, and GIF define the color of individual pixels. A 100
× 100
PNG image requires 10,000 pixels. Each pixel requires four bytes for red, green, blue and transparency, so the resulting file is 40,000 bytes (plus a little more for metadata). Compression is applied to reduce the file size: PNG and GIF use ZIP-like lossless compression, while JPG is lossy and removes less noticeable details (WebP can use either method).
Bitmaps are ideal for photographs and more complex images, but definition is lost as images are enlarged.
SVGs are vector images defined in XML. Points, lines, curves, paths, ellipses, rectangles, text, etc. are drawn on an SVG canvas. For example:
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 800 600">
<circle cx="400" cy="300" r="250" stroke-width="20" stroke="#f00" fill="#ff0" />
</svg>
The viewBox
defines a co-ordinate space. In this example, an 800
× 600
area starting at position 0,0
has a yellow circle with a red border and a 250
unit radius drawn in the center:
These are the benefits of vectors over bitmaps:
- the SVG above uses fewer than 150 bytes, which is considerably smaller than an equivalent PNG or JPG
- SVG backgrounds are transparent by default
- the image can scale to any size without losing quality
- SVG code/elements can be generated and manipulated on the server (using any language) or browser (using CSS and JavaScript)
- in terms of accessibility and SEO, text and drawing elements are machine and human-readable.
SVG images are ideal for logos, charts, icons, and simpler diagrams. Only photographs are generally impractical, although SVGs have been used for lazy-loading placeholders.
SVG Tools
It’s useful to understand the basics of SVG drawing, but you’ll soon want to create more complex shapes with an editor that can generate the code. Options include:
- Adobe Illustrator (commercial)
- Affinity Designer (commercial)
- Sketch (commercial)
- Inkscape (open source)
- Gravit Designer (commercial with free plan, online)
- Vectr (free, online)
- SVG-Edit ( open source, online)
- Boxy SVG (commercial, online but Blink browsers only)
- Vecteezy (commercial with free plan, online but Blink browsers only)
- SVG charting libraries, which generally create SVG charts using data passed to JavaScript functions.
Each tool has different strengths, and you’ll get differing results for seemingly identical images. In general, more complex images require more complex software.
The resulting code can usually be simplified and minimized further using SVGO (plugins are available for most build tools), or Jake Archibold’s SVGOMG interactive tool.
SVGs as Static Images
When used within an HTML <img>
tag or CSS background-url
, SVGs act identically to bitmaps:
<!-- HTML image -->
<img src="myimage.svg" alt="a vector graphic" />
/* CSS background */
.myelement {
background-image: url("mybackground.svg");
}
The browser will disable any scripts, links, and other interactive features embedded into the SVG file. You can manipulate that SVG using CSS in an identical way to other images using transform
, filters
, etc. The results are often superior to bitmaps because SVGs can be infinitely scaled.
CSS Inlined SVG Backgrounds
An SVG can be inlined directly in CSS code as a background image. This can be ideal for smaller, reusable icons and avoids additional HTTP requests. For example:
.mysvgbackground {
background: url('data:image/svg+xml;utf8,<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 800 600"><circle cx="400" cy="300" r="50" stroke-width="5" stroke="#f00" fill="#ff0" /></svg>') center center no-repeat;
}
Standard UTF-8 text encoding (rather than base64) can be used, so it’s easier to edit the SVG image if necessary.
The process is usually more practical using a tool such as the PostCSS assets plugin.
CSS with SVG: Responsive SVG Images
When creating a responsive website, images are often sized to the width of their container or the image itself (whichever is smaller). This is achieved in CSS using:
img {
display: block;
max-width: 100%;
height: auto;
}
However, an SVG used in an <img>
tag may have no implicit dimensions. You might discover the max-width
is calculated as zero and the image disappears entirely. To fix the problem, ensure a default width
and height
is defined in the <svg>
tag:
<svg xmlns="https://www.w3.org/2000/svg" width="400" height="300">
HTML-inlined SVG Images
SVGs can be placed directly into HTML markup. The image then becomes part of the DOM and can be manipulated using CSS and JavaScript:
<p>SVG is inlined directly into the HTML:</p>
<svg id="invader" xmlns="https://www.w3.org/2000/svg" viewBox="35.4 35.4 195.8 141.8">
<path d="M70.9 35.4v17.8h17.7V35.4H70.9zm17.7 17.8v17.7H70.9v17.7H53.2V53.2H35.4V124h17.8v17.7h17.7v17.7h17.7v-17.7h88.6v17.7h17.7v-17.7h17.7V124h17.7V53.2h-17.7v35.4h-17.7V70.9h-17.7V53.2h-17.8v17.7H106.3V53.2H88.6zm88.6 0h17.7V35.4h-17.7v17.8zm17.7 106.2v17.8h17.7v-17.8h-17.7zm-124 0H53.2v17.8h17.7v-17.8zm17.7-70.8h17.7v17.7H88.6V88.6zm70.8 0h17.8v17.7h-17.8V88.6z"/>
<path d="M319 35.4v17.8h17.6V35.4H319zm17.6 17.8v17.7H319v17.7h-17.7v17.7h-17.7V159.4h17.7V124h17.7v35.4h17.7v-17.7H425.2v17.7h17.7V124h17.7v35.4h17.7V106.3h-17.7V88.6H443V70.9h-17.7V53.2h-17.7v17.7h-53.2V53.2h-17.7zm88.6 0h17.7V35.4h-17.7v17.8zm0 106.2h-35.5v17.8h35.5v-17.8zm-88.6 0v17.8h35.5v-17.8h-35.5zm0-70.8h17.7v17.7h-17.7V88.6zm70.9 0h17.7v17.7h-17.7V88.6z"/>
</svg>
<p>The SVG is now part of the DOM.</p>
In this case, width
or height
attributes are not necessary because the dimensions can be directly controlled. For example:
#invader {
display: block;
width: 200px;
height: auto;
}
#invader path {
stroke-width: 0;
fill: #080;
}
However, adding the dimensions ensures the SVG is not sized inappropriately when CSS is not applied.
See the Pen HTML-Inlined SVG by SitePoint (@SitePoint) on CodePen.
SVG elements such as paths, circles, rectangles etc. can be targeted by CSS selectors and have the styling modified using standard SVG attributes as CSS properties. For example:
/* CSS styling for all SVG circles */
circle {
stroke-width: 20;
stroke: #f00;
fill: #ff0;
}
This overrides any attributes defined within the SVG because the CSS has a higher specificity. SVG CSS styling offers several benefits:
- attribute-based styling can be removed from the SVG entirely to reduce the page weight
- CSS styling can be reused across any number of SVGs on any number of pages
- the whole SVG or individual elements of the image can have CSS effects applied using
:hover
,transition
,animation
etc.
SVG Sprites
A single SVG file can contain any number of separate images. For example, this folders.svg
file contains folder icons generated by IcoMoon. Each is contained within a separate <symbol>
container with an ID which can be targeted:
<svg xmlns="https://www.w3.org/2000/svg">
<defs>
<symbol id="icon-folder" viewBox="0 0 32 32">
<title>folder</title>
<path d="M14 4l4 4h14v22h-32v-26z"></path>
</symbol>
<symbol id="icon-folder-open" viewBox="0 0 32 32">
<title>open</title>
<path d="M26 30l6-16h-26l-6 16zM4 12l-4 18v-26h9l4 4h13v4z"></path>
</symbol>
<symbol id="icon-folder-plus" viewBox="0 0 32 32">
<title>plus</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-4v4h-4v-4h-4v-4h4v-4h4v4h4v4z"></path>
</symbol>
<symbol id="icon-folder-minus" viewBox="0 0 32 32">
<title>minus</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-12v-4h12v4z"></path>
</symbol>
<symbol id="icon-folder-download" viewBox="0 0 32 32">
<title>download</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM16 27l-7-7h5v-8h4v8h5l-7 7z"></path>
</symbol>
<symbol id="icon-folder-upload" viewBox="0 0 32 32">
<title>upload</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM16 15l7 7h-5v8h-4v-8h-5l7-7z"></path>
</symbol>
</defs>
</svg>
The SVG file can be referenced as an external, cached resource in an HTML page. For example, here’s how to show the folder icon at #icon-folder
:
<svg class="folder" viewBox="0 0 100 100">
<use xlink:href="folders.svg#icon-folder"></use>
</svg>
And here’s how to style it with CSS:
svg.folder { fill: #f7d674; }
The method has a couple of drawbacks:
- It fails in IE.
- CSS styling only applies to the
<svg>
element containing the<use>
. Thefill
here makes every element of the icon the same color.
To solve these issues, the SVG sprite can be embedded within page HTML then hidden using display: none
or similar techniques. An individual icon can be placed by referencing the ID:
<svg><use xlink:href="#icon-folder"></use></svg>
See the Pen SVG sprites by SitePoint (@SitePoint) on CodePen.
This works in all modern browsers including IE9+ and it becomes possible to style individual elements within each icon using CSS.
Unfortunately, the SVG set is no longer cached and must be reproduced on every page where an icon is required. The solution (to this solution!) is to load the SVG using Ajax — which is then cached — and inject it into the page. The IcoMoon download provides a JavaScript library, or you could use SVG for Everybody.
SVG Effects on HTML Content
SVG has long supported:
- masks: altering the visibility of parts of an element
- clipping: removing segments of an element so a standard regular box becomes any other shape
- filters: graphical effects such as blurring, brightness, shadows, etc.
These effects have been ported to the CSS mask
, clip-path
, and filter
properties. However, it’s still possible to target an SVG selector:
/* CSS */
.myelement {
clip-path: url(#clip);
}
This references an effect within an HTML-embedded SVG:
<svg xmlns="https://www.w3.org/2000/svg" aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;">
<defs>
<clipPath id="clip">
<text x="0" y="200" font-family="Arial" font-size="10em" font-weight="800">Text Clip</text>
</clipPath>
</defs>
</svg>
It produces effects such as clipped text with an image or gradient background:
See the Pen SVG clipping by SitePoint (@SitePoint) on CodePen.
Portable SVGs
Finally, a standalone SVG file can contain text, CSS, JavaScript, bitmap images, and even base64-encoded fonts! Anything outside the realms of XML should be contained within <![CDATA[
… ]]>
sections.
Consider the following invader.svg
file. It defines CSS styling with hover effects and a JavaScript animation which changes the viewBox
between two states:
<svg id="invader" xmlns="https://www.w3.org/2000/svg" viewBox="35.4 35.4 195.8 141.8">
<!-- invader images: https://github.com/rohieb/space-invaders !-->
<style>/* <![CDATA[ */
path {
stroke-width: 0;
fill: #080;
}
path:hover {
fill: #c00;
}
/* ]]> */</style>
<path d="M70.9 35.4v17.8h17.7V35.4H70.9zm17.7 17.8v17.7H70.9v17.7H53.2V53.2H35.4V124h17.8v17.7h17.7v17.7h17.7v-17.7h88.6v17.7h17.7v-17.7h17.7V124h17.7V53.2h-17.7v35.4h-17.7V70.9h-17.7V53.2h-17.8v17.7H106.3V53.2H88.6zm88.6 0h17.7V35.4h-17.7v17.8zm17.7 106.2v17.8h17.7v-17.8h-17.7zm-124 0H53.2v17.8h17.7v-17.8zm17.7-70.8h17.7v17.7H88.6V88.6zm70.8 0h17.8v17.7h-17.8V88.6z"/>
<path d="M319 35.4v17.8h17.6V35.4H319zm17.6 17.8v17.7H319v17.7h-17.7v17.7h-17.7V159.4h17.7V124h17.7v35.4h17.7v-17.7H425.2v17.7h17.7V124h17.7v35.4h17.7V106.3h-17.7V88.6H443V70.9h-17.7V53.2h-17.7v17.7h-53.2V53.2h-17.7zm88.6 0h17.7V35.4h-17.7v17.8zm0 106.2h-35.5v17.8h35.5v-17.8zm-88.6 0v17.8h35.5v-17.8h-35.5zm0-70.8h17.7v17.7h-17.7V88.6zm70.9 0h17.7v17.7h-17.7V88.6z"/>
<script>/* <![CDATA[ */
const
viewX = [35.4, 283.6],
animationDelay = 500,
invader = document.getElementById('invader');
let frame = 0;
setInterval(() => {
frame = ++frame % 2;
invader.viewBox.baseVal.x = viewX[frame];
}, animationDelay);
/* ]]> */</script>
</svg>
When referenced in an HTML <img>
or CSS background, the SVG becomes a static image of the initial state (in essence, the first animation frame):
However, open the image in its own browser tab and all the effects will return.
This could be useful for distributing images, demonstrations, or small documents which require some embedded interactivity.
Sophisticated SVGs
SVGs offer a wide range of technical possibilities — both within and outside of web pages. It becomes possible to style and animate the whole SVG image or individual drawing elements using CSS and/or JavaScript.
This article describes ways to manipulate SVG images, but they’re regularly used for smaller visual enhancements, such as:
- form focus highlights and validation
- turning a hamburger menu into a an
X
close icon - lava-lamp–like morphing.
Despite the age of SVG technology, web developers are still discovering interesting ways to transform boring block-based pages with subtle effects through using CSS and SVG images. Let me know on Twitter if you create any good demonstrations.
Frequently Asked Questions (FAQs) about CSS with SVG
What is the difference between using SVG in CSS and HTML?
SVG, or Scalable Vector Graphics, can be used both in CSS and HTML, but they serve different purposes. In HTML, SVG is used to define vector-based graphics for the web. It uses XML to describe 2D graphics and graphical applications. On the other hand, when SVG is used in CSS, it’s primarily for styling web pages. It can be used to create background images, icons, or even complex animations. The main difference lies in the application – HTML for creating the graphics, and CSS for styling them.
How can I animate SVG with CSS?
Animating SVG with CSS is similar to animating any other HTML element. You can use keyframes and the animation property in CSS to create smooth, scalable animations. Here’s a simple example of how you can animate an SVG element:@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
svg {
animation: spin 2s linear infinite;
}
In this example, the SVG element will continuously spin in a circle.
Can I use CSS to change the color of SVG?
Yes, you can use CSS to change the color of SVG elements. You can use the fill property in CSS to change the color of the SVG. Here’s an example:svg {
fill: blue;
}
In this example, the SVG will be filled with blue color.
How can I use SVG as a background image in CSS?
You can use SVG as a background image in CSS by using the url() function in the background-image property. Here’s an example:body {
background-image: url('image.svg');
}
In this example, the SVG file named ‘image.svg’ will be used as the background image.
Can I use media queries with SVG?
Yes, you can use media queries with SVG to make your SVG graphics responsive. You can adjust the size, position, or even the color of the SVG based on the screen size or other media features. Here’s an example:@media (max-width: 600px) {
svg {
width: 50%;
height: auto;
}
}
In this example, the SVG will take up 50% of the width of the screen when the screen size is 600px or less.
How can I make SVG responsive?
To make SVG responsive, you can use the viewBox attribute in the SVG element. The viewBox attribute allows you to specify the aspect ratio and coordinate system of the SVG. By using this attribute, the SVG will scale up and down to fit its container while maintaining its aspect ratio. Here’s an example:<svg viewBox="0 0 100 100">
<!-- SVG content -->
</svg>
In this example, the SVG will maintain a 1:1 aspect ratio and will scale to fit its container.
Can I use CSS filters on SVG?
Yes, you can use CSS filters on SVG. CSS filters provide various visual effects like blur, brightness, contrast, and more. Here’s an example of how you can apply a blur filter to an SVG:svg {
filter: blur(5px);
}
In this example, the SVG will have a blur effect.
How can I use SVG in CSS pseudo-elements?
You can use SVG in CSS pseudo-elements by using the content property and the url() function. Here’s an example:::before {
content: url('image.svg');
}
In this example, the SVG file named ‘image.svg’ will be inserted before the content of the element.
Can I use SVG in CSS gradients?
No, you cannot directly use SVG in CSS gradients. However, you can create gradient effects in SVG itself using the <linearGradient>
or <radialGradient>
elements, and then use the SVG as a background image or an image in your CSS.
Can I use SVG in CSS transforms?
Yes, you can use SVG in CSS transforms. You can apply 2D or 3D transformations to SVG elements such as rotate, scale, skew, or translate. Here’s an example:svg {
transform: rotate(45deg);
}
In this example, the SVG will be rotated 45 degrees clockwise.
Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's created enterprise specifications, websites and online applications for companies and organisations including the UK Parliament, the European Parliament, the Department of Energy & Climate Change, Microsoft, and more. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler.