About The Author

Sara Soueidan is a freelance front-end web developer, consultant, author and speaker from Lebanon — focusing on HTML5, SVG, CSS, and JavaScript. She’s a … More about Sara

Styling And Animating SVGs With CSS

Quick Summary

Why is it so important to optimize your SVGs? Also, why even put in the effort to make them accessible? In this article, Sara Soueidan explais why, and also how to style and animate with CSS.

Table of Contents
Membership counter

Members support Smashing

Wonderful, friendly people who keep this lil' site alive — and get smarter every day.

Are you smashing, too? →

CSS can be used to style and animate scalable vector graphics, much like it is used to style and animate HTML elements. In this article, which is a modified transcript of a talk I recently gave at CSSconf EU and From the Front, I’ll go over the prerequisites and techniques for working with CSS in SVG.

I’ll also go over how to export and optimize SVGs, techniques for embedding them and how each one affects the styles and animations applied, and then we’ll actually style and animate with CSS.

Further Reading on SmashingMag:

Introduction

Scalable vector graphics (SVG) is an XML-based vector image format for two-dimensional graphics, with support for interactivity and animation. In other words, SVGs are XML tags that render shapes and graphics, and these shapes and graphics can be interacted with and animated much like HTML elements can be.

Animations and interactivity can be added via CSS or JavaScript. In this article, we’ll focus on CSS.

There are many reasons why SVGs are great and why you should be using them today:

  • SVG graphics are scalable and resolution-independent. They look great everywhere, from high-resolution “Retina” screens to printed media.
  • SVGs have very good browser support. Fallbacks for non-supporting browsers are easy to implement, too, as we’ll see later in the article.
  • Because SVGs are basically text, they can be gzipped, making the files smaller that their bitmap counterparts (JPEG and PNG).
  • SVGs are interactive and styleable with CSS and JavaScript.
  • SVG comes with built-in graphics effects such as clipping and masking operations, background blend modes, and filters. This is basically the equivalent of having Photoshop photo-editing capabilities right in the browser.
  • SVGs are accessible. In one sense, they have a very accessible DOM API, which makes them a perfect tool for infographics and data visualizations and which gives them an advantage over HTML5 Canvas because the content of the latter is not accessible. In another sense, you can inspect each and every element in an SVG using your favorite browser’s developer tools, just like you can inspect HTML elements. And SVGs are accessible to screen readers if you make them so. We’ll go over accessibility a little more in the last section of this article.
  • Several tools are available for creating, editing and optimizing SVGs. And other tools make it easier to work with SVGs and save a lot of time in our workflows. We’ll go over some of these tools next.

Exporting SVGs From Graphics Editors And Optimizing Them

The three most popular vector graphics editors are:

  1. Adobe Illustrator,
  2. Inkscape,
  3. Sketch.

Adobe Illustrator is a paid application from Adobe. It is a highly popular editor, with a nice UI and many capabilities that make it the favorite of most designers.

Inkscape is a popular free alternative. Even though its UI is not as nice as Illustrator’s, it has everything you need to work with vector graphics.

Sketch is a Mac OS X-only graphics app. It is not free either, but it has been making the rounds among designers lately and gaining popularity, with a lot of resources and tools being created recently to improve the workflow.

Choose any editor to create your SVGs. After choosing your favorite editor and creating an SVG but before embedding it on a web page, you need to export it from the editor and clean it up to make it ready to work with.

I’ll refer to exporting and optimizing an SVG created in Illustrator. But the workflow applies to pretty much any editor, except for the Illustrator-specific options we’ll go over next.

To export an SVG from Illustrator, start by going to “File” → “Save as,” and then choose “.svg” from the file extensions dropdown menu. Once you’ve chosen the .svg extension, a panel will appear containing a set of options for exporting the SVG, such as which version of SVG to use, whether to embed images in the graphic or save them externally and link to them in the SVG, and how to add the styles to the SVG (by using presentation attributes or by using CSS properties in a <style> element).

The following image shows the best settings to choose when exporting an SVG for the web:

01-Ai-options-quick-preview-opt

The reasons why the options above are best are explained in Michaël Chaize’s excellent article “Export SVG for the Web With Illustrator CC.”

Whichever graphics editor you choose, it will not output perfectly clean and optimized code. SVG files, especially ones exported from editors, usually contain a lot of redundant information, such as meta data from the editor, comments, empty groups, default values, non-optimal values and other stuff that can be safely removed or converted without affecting the rendering of the SVG. And if you’re using an SVG that you didn’t create yourself, then the code is almost certainly not optimal, so using a standalone optimization tool is advisable.

Several tools for optimizing SVG code are out there. Peter Collingridge’s SVG Editor is an online tool that you input SVG code into either directly or by uploading an SVG file and that then provides you with several optimization options, like removing redundant code, comments, empty groups, white space and more. One option allows you to specify the number of decimal places of point coordinates.

02-svg-editor-quick-preview-opt
(View large version)

Peter’s optimizer can also automatically move inline SVG properties to a style block at the top of the document. The nice thing about it is that, when you check an option, you can see the result of the optimization live, which enables you to better decide which optimizations to make. Certain optimizations could end up breaking your SVG. For example, one decimal place should normally be enough. If you’re working with a path-heavy SVG file, reducing the number of decimal places from four to one could slash your file’s size by as much as half. However, it could also entirely break the SVG. So, being able to preview an optimization is a big plus.

Peter’s tool is an online one. If you’d prefer an offline tool, try SVGO (the “O” is for “optimizer”), a Node.js-based tool that comes with a nice and simple drag-and-drop GUI. If you don’t want to use an online tool, this one is a nice alternative.

The following screenshot (showing the path from the image above) is a simple before-and-after illustration of how much Peter’s tool optimizes SVG.

03-optimized-path-opt

Notice the size of the original SVG compared to the optimized version. Not to mention, the optimized version is much more readable.

After optimizing the SVG, it’s ready to be embedded on a web page and further customized or animated with CSS.

Styling SVGs With CSS

The line between HTML and CSS is clear: HTML is about content and structure, and CSS is about the look. SVG blurs this line, to say the least. SVG 1.1 did not require CSS to style SVG nodes — styles were applied to SVG elements using attributes known as “presentation attributes.”

Presentation attributes are a shorthand for setting a CSS property on an element. Think of them as special style properties. They even contribute to the style cascade, but we’ll get to that shortly.

The following example shows an SVG snippet that uses presentation attributes to style the “border” (stroke) and “background color” (fill) of a star-shaped polygon:


<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0 0 300 300">
  <polygon
fill = "#FF931E"
stroke = "#ED1C24"
stroke-width = "5"
points = "279.1,160.8 195.2,193.3 174.4,280.8   117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/>
</svg>

The fill, stroke and stroke-width attributes are presentation attributes.

In SVG, a subset of all CSS properties may be set by SVG attributes, and vice versa. The SVG specification lists the SVG attributes that may be set as CSS properties. Some of these attributes are shared with CSS, such as opacity and transform, among others, while some are not, such as fill, stroke and stroke-width, among others.

In SVG 2, this list will include x, y, width, height, cx, cy and a few other presentation attributes that were not possible to set via CSS in SVG 1.1. The new list of attributes can be found in the SVG 2 specification.

Another way to set the styles of an SVG element is to use CSS properties. Just like in HTML, styles may be set on an element using inline style attributes:


<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 300px; height: 300px;" viewBox="0 0 300 300">
<polygon
  style = "fill: #FF931E; stroke: #ED1C24; stroke-width: 5;"
  points = "279.1,160.8 195.2,193.3 174.4,280.8   117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/>
</svg>

Styles may also be set in rule sets in a <style> tag. The <style> tag can be placed in the <svg> tag:


<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0 0 300 300">
  <style type="text/css">
  <![CDATA[
  selector {/* styles */}
  ]]>
  </style>
  <g id=".."> … </g>
</svg>

And it can be placed outside of it, if you’re embedding the SVG inline in the document:


<!DOCTYPE html><!-- HTML5 document -->
<html>
<head> … </head>
<body>
<style type="text/css">
  /* style rules */
</style>
<!-- xmlns is optional in an HTML5 document →
<svg viewBox="0 0 300 300">
<!-- SVG content -->
</svg>
</body>
</html>

And if you want to completely separate style from markup, then you could always link to an external style sheet from the SVG file, using the <?xml-stylesheet> tag, as shown below:


<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/css" href="style.css"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width=".." height=".." viewBox="..">
  <!-- SVG content -->
</svg>

Style Cascades

We mentioned earlier that presentation attributes are sort of special style properties and that they are just shorthand for setting a CSS property on an SVG node. For this reason, it only makes sense that SVG presentation attributes would contribute to the style cascade.

Indeed, presentation attributes count as low-level “author style sheets” and are overridden by any other style definitions: external style sheets, document style sheets and inline styles.

The following diagram shows the order of styles in the cascade. Styles lower in the diagram override those above them. As you can see, presentation attribute styles are overridden by all other styles except for those specific to the user agent.

04-diagram-opt

For example, in the following code snippet, an SVG circle element has been drawn. The fill color of the circle will be deep pink, which overrides the blue fill specified in the presentation attribute.


<circle cx="100" cy="100" r="75" fill="blue" style="fill:deepPink;" />

Selectors

Most CSS selectors can be used to select SVG elements. In addition to the general type, class and ID selectors, SVGs can be styled using CSS2’s dynamic pseudo-classes (:hover, :active and :focus) and pseudo-classes (:first-child, :visited, :link and :lang. The remaining CSS2 pseudo-classes, including those having to do with generated content (such as ::before and ::after), are not part of the SVG language definition and, hence, have no effect on the style of SVGs.

The following is a simple animation of the fill color of a circle from deep pink to green when it is hovered over using the tag selector and the :hover pseudo-class:


<style>
circle {
  fill: deepPink;
  transition: fill .3s ease-out;
}

circle:hover {
  fill: #009966;
}
</style>

Much more impressive effects can be created. A simple yet very nice effect comes from the Iconic icons set, in which a light bulb is lit up when hovered over. A demo of the effect is available.

Notes

Because presentation attributes are expressed as XML attributes, they are case-sensitive. For example, when specifying the fill color of an element, the attribute must be written as fill=“…” and not Fill=“…”.

Furthermore, keyword values for these attributes, such as the italic in font-style=“italic”, are also case-sensitive and must be specified using the exact case defined in the specification that defines that value.

All other styles specified as CSS properties — whether in a style attribute or a <style> tag or in an external style sheet — are subject to the grammar rules specified in the CSS specifications, which are generally less case-sensitive. That being said, the SVG “Styling” specification recommends using the exact property names (usually, lowercase letters and hyphens) as defined in the CSS specifications and expressing all keywords in the same case, as required by presentation attributes, and not taking advantage of CSS’s ability to ignore case.

Animating SVGs With CSS

SVGs can be animated the same way that HTML elements can, using CSS keyframes and animation properties or using CSS transitions.

In most cases, complex animations will usually contain some kind of transformation — a translation, a rotation, scaling and/or skewing.

In most respects, SVG elements respond to transform and transform-origin in the same way that HTML elements do. However, a few inevitable differences result from the fact that, unlike HTML elements, SVG elements aren’t governed by a box model and, hence, have no margin, border, padding or content boxes.

By default, the transform origin of an HTML element is at (50%, 50%), which is the element’s center. By contrast, an SVG element’s transform origin is positioned at the origin of the user’s current coordinate system, which is the (0, 0) point, in the top-left corner of the canvas.

Suppose we have an HTML <div> and an SVG <rect> element:


<!DOCTYPE html>
…
<div style="width: 100px; height: 100px; background-color: orange"> </div>
<svg style="width: 150px; height: 150px; background-color: #eee">
  <rect width="100" height="100" x="25" y="25" fill="orange" />
</svg>

If were were to rotate both of them by 45 degrees, without changing the default transform origin, we would get the following result (the red circle indicates the position of the transform origin):

05-transform-svg-html-quick-preview-opt
(View large version)

What if we wanted to rotate the SVG element around its own center, rather than the top-left corner of the SVG canvas? We would need to explicitly set the transform origin using the transform-origin property.

Setting the transform origin on an HTML element is straightforward: Any value you specify will be set relative to the element’s border box.

In SVG, the transform origin can be set using either a percentage value or an absolute value (for example, pixels). If you specify a transform-origin value in percentages, then the value will be set relative to the element’s bounding box, which includes the stroke used to draw its border. If you specify the transform origin in absolute values, then it will be set relative to the SVG canvas’ current coordinate system of the user.

If we were to set the transform origin of the <div> and <rect> from the previous example to the center using percentage values, we would do this:


<!DOCTYPE html>
<style>
  div, rect {
  transform-origin: 50% 50%;
}
</style>

The resulting transformation would look like so:

06-transform-svg-html-quick-preview-opt
(View large version)

That being said, at the time of writing, setting the transform origin in percentage values currently does not work in Firefox. This is a known bug. So, for the time being, your best bet is to use absolute values so that the transformations behave as expected. You can still use percentage values for WebKit browsers, though.

In the following example, we have a pinwheel on a stick that we’ll rotate using CSS animation. To have the wheel rotate around its own center, we’ll set its transform origin in pixels and percentages:


<svg>
<style>
.wheel {
  transform-origin: 193px 164px;
  -webkit-transform-origin: 50% 50%;
  -webkit-animation: rotate 4s cubic-bezier(.49,.05,.32,1.04) infinite alternate;
  animation: rotate 4s cubic-bezier(.49,.05,.32,1.04) infinite alternate;
}

@-webkit-keyframes rotate {
  50% {
    -webkit-transform: rotate(360deg);
  }
}

@keyframes rotate {
  50% {
    transform: rotate(360deg);
  }
}

</style>
<!-- SVG content -->
</svg>

You can check out the live result on Codepen. Note that, at the time of writing, CSS 3D transformations are not hardware-accelerated when used on SVG elements; they have the same performance profile as SVG transform attributes. However, Firefox does accelerate transforms on SVGs to some extent.

Animating SVG Paths

There is no way to animate an SVG path from one shape to another in CSS. If you want to morph paths — that is, animate from one path to another — then you will need to use JavaScript for the time being. If you do that, I recommend using Snap.svg by Dmitry Baranovskiy, the same person behind the SVG library Raphaël.

Snap.svg is described as being to SVG what jQuery is to HTML, and it makes dealing with SVGs and its quirks a lot easier.

That being said, you could create an animated line-drawing effect using CSS. The animation would require you to know the total length of the path you’re animating and then to use the stroke-dashoffset and stroke-dasharray SVG properties to achieve the drawing effect. Once you know the length of the path, you can animate it with CSS using the following rules:


#path {
stroke-dasharray: pathLength;
stroke-dashoffset: pathLength;
/* transition stroke-dashoffset */
transition: stroke-dashoffset 2s linear;
}

svg:hover #path{
  stroke-dashoffset: 0;
}

In the example above, the path is drawn over the course of two seconds when the SVG is hovered over.

In the next demo, we’ll use the same technique and then use a CSS transition — with a delay — to light up the bulb once the path’s animation ends.


#cable {
  stroke: #FFF2B1;
  stroke-dasharray: 4000 4000;  
  stroke-dashoffset: 4000;
  stroke-width: 4;
  transition: stroke-dashoffset 8s linear;
}

svg:hover #cable {
  stroke-dashoffset: 0;
}

/* turn lamp on */
.inner-lamp{
  fill:grey;
  transition: fill .5s ease-in 6s;
}

svg:hover .inner-lamp {
  fill: #FBFFF8;
}
/* … */

You can view the live demo on JS Bin. Note that you can also write stroke-dasharray: 4000; instead of stroke-dasharray: 4000 4000 — if the two line and gap values are equal, then you can specify only one value to be applied to both.

Sometimes, you might not know the exact length of the path to animate. In this case, you can use JavaScript to retrieve the length of the path using the getTotalLength() method:


var path = document.querySelector('.drawing-path');
path.getTotalLength();
//set CSS properties up
path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;
//set transition up
path.style.transition = 'stroke-dashoffset 2s ease-in-out';
// animate
path.style.strokeDashoffset = '0';

The snippet above is a very simplified example showing that you can do the same thing we did with CSS but using JavaScript.

Jake Archibald has written an excellent article explaining the technique in more detail. Jake includes a nice interactive demo that makes it easy to see exactly what’s going on in the animation and how the two SVG properties work together to achieve the desired effect. I recommend reading his article if you’re interested in learning more about this technique.

Embedding SVGs

An SVG can be embedded in a document in six ways, each of which has its own pros and cons.

The reason we’re covering embedding techniques is because the way you embed an SVG will determine whether certain CSS styles, animations and interactions will work once the SVG is embedded.

An SVG can be embedded in any of the following ways:

1. as an image using the <img> tag:

<img src="mySVG.svg" alt="" />

2. as a background image in CSS:

.el {background-image: url(mySVG.svg);}

3. as an object using the <object> tag:

<figure class="aspect-ratio"><object type="image/svg+xml" data="mySVG.svg"><!-- fallback here --></figure></object>

4. as an iframe using an <iframe> tag:

<iframe src="mySVG.svg"><!-- fallback here --></iframe>

5. using the <embed> tag:

<embed type="image/svg+xml" src="mySVG.svg" />

6. inline using the <svg> tag:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" …> </svg>

The <object> tag is the primary way to include an external SVG file. The main advantage of this tag is that there is a standard mechanism for providing an image (or text) fallback in case the SVG does not render. If the SVG cannot be displayed for any reason — such as because the provided URI is wrong — then the browser will display the content between the opening and closing <object> tags.


<object type="image/svg+xml" data="mySVG.svg">
  <img src="fallback-image.png" alt="…" />
</object>

If you intend using any advanced SVG features, such as CSS or scripting, the then HTML5 <object> tag is your best bet.

Because browsers can render SVG documents in their own right, embedding and displaying an SVG using an iframe is possible. This might be a good method if you want to completely separate the SVG code and script from your main page. However, manipulating an SVG image from your main page’s JavaScript becomes a little more difficult and will be subject to the same-origin policy.

The <iframe> tag, just like the <object> tag, comes with a default way to provide a fallback for browsers that don’t support SVG, or those that do support it but can’t render it for whatever reason.


<iframe src="mySVG.svg">
  <img src="fallback-image.png" alt="…" />
</iframe>

The <embed> tag was never a part of any HTML specification, but it is still widely supported. It is intended for including content that needs an external plugin to work. The Adobe Flash plugin requires the <embed> tag, and supporting this tag is the only real reason for its use with SVG. The <embed> tag does not come with a default fallback mechanism.

An SVG can also be embedded in a document inline — as a “code island” — using the <svg> tag. This is one of the most popular ways to embed SVGs today. Working with inline SVG and CSS is a lot easier because the SVG can be styled and animated by targeting it with style rules placed anywhere in the document. That is, the styles don’t need to be included between the opening and closing <svg> tags to work; whereas this condition is necessary for the other techniques.

Embedding SVGs inline is a good choice, as long as you’re willing to add to the size of the page and give up backwards compatibility (since it does not come with a default fallback mechanism either). Also, note that an inline SVG cannot be cached.

An SVG embedded with an <img> tag and one embedded as a CSS background image are treated in a similar way when it comes to CSS styling and animation. Styles and animations applied to an SVG using an external CSS resource will not be preserved once the SVG is embedded.

The following table shows whether CSS animations and interactions (such as hover effects) are preserved when an SVG is embedded using one of the six embedding techniques, as compared to SVG SMIL animations. The last column shows that, in all cases, SVG animations (SMIL) are preserved.


Table showing whether CSS styles, animations and interactions are preserved for each of the SVG embedding techniques.
CSS Interactions (e.g. :hover) CSS Animations SVG Animations (SMIL)
<img> No Yes only if inside <svg> Yes
CSS background image No Yes only if inside <svg> Yes
<object> Yes only if inside <svg> Yes only if inside <svg> Yes
<iframe> Yes only if inside <svg> Yes only if inside <svg> Yes
<embed> Yes only if inside <svg> Yes only if inside <svg> Yes
<svg> (inline) Yes Yes Yes

The behavior indicated in the table above is the standard behavior. However, implementations may differ between browsers, and bugs may exist.

Note that, even though SMIL animations will be preserved, SMIL interactions will not work for an SVG embedded as an image (i.e. <img> or via CSS).

Making SVGs Responsive

After embedding an SVG, you need to make sure it is responsive.

Depending on the embedding technique you choose, you might need to apply certain hacks and fixes to get your SVG to be cross-browser responsive. The reason for this is that the way browsers determine the dimensions of an SVG differs for some embedding techniques, and SVG implementations among browsers also differ. Therefore, the way SVG is handled is different and requires some style tweaking to make it behave consistently across all browsers.

I won’t get into details of browser inconsistencies, for the sake of brevity. I will only cover the fix or hack needed for each embedding technique to make the SVG responsive in all browsers for that technique. For a detailed look at the inconsistencies and bugs, check out my article on Codrops.

Whichever technique you choose, the first thing you’ll need to do is remove the height and width attributes from the root <svg> element.

You will need to preserve the viewBox attribute and set the preserveAspectRatio attribute to xMidYMid meet — if it isn’t already set to that value. Note that you might not need to explicitly set preserveAspectRatio to xMidYMid meet at all because it will default to this value anyway if you don’t change it.

When an SVG is embedded as a CSS background image, no extra fixes or hacks are needed. It will behave just like any other bitmap background image and will respond to CSS’ background-image properties as expected.

An SVG embedded using an <img> tag will automatically be stretched to the width of the container in all browsers (once the width has been removed from the <svg>, of course). It will then scale as expected and be fluid in all browsers except for Internet Explorer (IE). IE will set the height of the SVG to 150 pixels, preventing it from scaling correctly. To fix this, you will need to explicitly set the width to 100% on the <img>.


<img src="mySVG.svg" alt="SVG Description." />
img {
  width: 100%;
}

The same goes for an SVG embedded using an <object> tag. For the same reason, you will also need to set the width of the <object> to 100%:


object {
  width: 100%;
}

Even though <iframe> has a lot in common with <object>, browsers seem to handle it differently. For it, all browsers will default to the default size for replaced elements in CSS, which is 300 by 150 pixels.

The only way to make an iframe responsive while maintaining the aspect ratio of the SVG is by using the “padding hack” pioneered by Thierry Koblentz on A List Apart. The idea behind the padding hack is to make use of the relationship of an element’s padding to its width in order to create an element with an intrinsic ratio of height to width.

When an element’s padding is set in percentages, the percentage is calculated relative to the width of the element, even when you set the top or bottom padding of the element.

To apply the padding hack and make the SVG responsive, the SVG needs to be wrapped in a container, and then you’ll need to apply some styles to the container and the SVG (i.e. the iframe), as follows:


<!-- wrap svg in a container -->
<div class="container">
  <iframe src="my_SVG_file.svg">
    <!-- fallback here -->
  </iframe>
</div>

.container {
  /* collapse the container's height */
  height: 0;        

  /* specify any width you want (a percentage value, basically) */     
  width: width-value;    

  /* apply padding using the following formula */
  /* this formula makes sure the aspect ratio of the container equals that of the SVG graphic */
  padding-top: (svg-height / svg-width) * width-value;
  position: relative;    /* create positioning context for SVG */
}

The svg-height and svg-width variables are the values of the height and width of the <svg>, respectively — the dimensions that we removed earlier. And the width-value is any width you want to give the SVG container on the page.

Finally, the SVG itself (the iframe) needs to be positioned absolutely inside the container:


iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

We position the iframe absolutely because collapsing the container’s height and then applying the padding to it would push the iframe beyond the boundaries of the container. So, to “pull it back up,” we position it absolutely. You can read more about the details in my article on Codrops.

Finally, an SVG embedded inline in an <svg> tag becomes responsive when the height and width are removed, because browsers will assume a width of 100% and will scale the SVG accordingly. However, IE has the same 150-pixel fixed-height issue for the <img> tag mentioned earlier; unfortunately, setting the width of the SVG to 100% is not sufficient to fix it this time.

To make the inline SVG fluid in IE, we also need to apply the padding hack to it. So, we wrap <svg> in a container, apply the padding-hack rules mentioned above to the container and, finally, position the <svg> absolutely inside it. The only difference here is that we do not need to explicitly set the height and width of <svg> after positioning it.


svg {
  position: absolute;
  top: 0;
  left: 0;
}

Using CSS Media Queries

SVG accepts and responds to CSS media queries as well. You can use media queries to change the styles of an SVG at different viewport sizes.

However, one important note here is that the viewport that the SVG responds to is the viewport of the SVG itself, not the page’s viewport, unless you are embedding the SVG inline in the document (using <svg>).

An SVG embedded with an <img>, <object> or <iframe> will respond to the viewport established by these elements. That is, the dimensions of these elements will form the viewport inside of which the SVG is to be drawn and, hence, will form the viewport to which the CSS media-query conditions will be applied. This is very similar in concept to element queries.

The following example includes a set of media queries inside an SVG that is then referenced using an <img> tag:


<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186">
  <style>
    @media all and (max-width: 50em) {
      /* select SVG elements and style them */
    } 
    @media all and (max-width: 30em) {
      /* styles  */
    }
  </style>
  <!-- SVG elements here -->
</svg>

When the SVG is referenced, it will get the styles specified in the media queries above when the <img> has a max-width of 50em or 30em, respectively.


<img src="my-logo.svg" alt="Page Logo." />

You can learn more about media queries inside SVGs in Andreas Bovens’s article for Dev.Opera.

Final Words

SVGs are images, and just as images can be accessible, so can SVGs. And making sure your SVGs are accessible is important, too.

I can’t emphasize this enough: Make your SVGs accessible. You can do several things to make that happen. For a complete and excellent guide, I recommend Leonie Watson’s excellent article on SitePoint. Her tips include using the <title> and <desc> tags in the <svg>, using ARIA attributes and much more.

In addition to accessibility, don’t forget to optimize your SVGs and provide fallbacks for non-supporting browsers. I recommend Todd Parker’s presentation.

Last but not least, you can always check support for different SVG features on Can I Use. I hope you’ve found this article to be useful. Thank you for reading.

Smashing Editorial (vf, al, il)