Using SVG with Media Queries – SitePoint

In HTML documents, we can show, hide, or rearrange parts of the page based on the conditions of the viewport. If the browser window is 480 pixels wide, for example, we might shift our navigation from a horizontal one to a vertical, collapsible list. We can do something similar when using SVG with media queries.
This article is an extract from Tiffany’s book CSS Master, 3rd Edition. Check it out if you’d like to master other advanced CSS3 features like Flexbox and Grid. You can read it online, download the ebook, or get the hard copy!
*      *      *
As well as using CSS with HTML, we can also use CSS with SVG, or Scalable Vector Graphics. SVG is a markup format for describing flat, two-dimensional images. Because it’s a markup language, it has a Document Object Model, and can be used with CSS.
By using CSS with SVG, we can change the appearance of SVG based on user interaction. Or we can use the same SVG document in multiple places, and show or hide portions of it based on the width of the viewport.
All major browser engines support the SVG 1.1 specification, and they have done for years. Support for features of SVG 2, on the other hand, is still a work in progress. Some of what we’ll discuss here has limited browser support at the time of writing. That may have changed by the time you’re reading this. Keep an eye on the Chromium meta issue — Implement SVG2 features — to track development progress in Chromium-based browsers. Watch the Support SVG 2 features meta issue to follow Firefox’s implementation work, and WebKit’s Implement SVG 2 meta issue for Safari. Issue trackers can be unpleasant to navigate, but for now they’re the best way to track SVG 2 support.
Before we go any further, however, let’s talk about what SVG is and why you should use it.
Vector Images versus Raster Images
Most of the images currently used on the Web are raster images, also known as bitmap images. Raster images are made up of pixels on a fixed grid, with a set number of pixels per inch. JPEG, WebP, GIF, and PNG are all examples of raster image formats.
Raster images are resolution dependent. A 144 PPI (pixels-per-inch) PNG image looks great on a device with a 144 PPI display resolution. When viewed on a higher resolution, 400 PPI display, however, that same image can look fuzzy. Raster images also have fixed dimensions and look best at their original size. Scaling a 150 by 150 pixel image up to 300 by 300 pixels distorts it.
Instead of using pixels on a grid, vector image formats describe the primitive shapes — circles, rectangles, lines, or paths — that make up an image, and their placement within the document’s coordinate system. As a result, vector images are resolution independent, and retain their quality regardless of display resolution or display dimensions.
Resolution independence is the biggest advantage of SVG. We can scale images up or down with no loss of quality. The same image looks great on both high and low PPI devices. That said, SVG is poorly suited to the amount of color data required for photographs. It’s best for drawings and shapes. Use it in place of PNG and GIF images, and as a more flexible replacement for icon fonts.
Another advantage of SVG is that it was designed to be used with other web languages. We can create, modify, and manipulate SVG images with JavaScript. Or, as we’ll see below, we can style and animate SVG using CSS.
Associating CSS with SVG Documents
Using CSS with SVG is a lot like using it with HTML. We can apply CSS using the style attribute of an SVG element, group CSS within a document using the


Embedding CSS in an SVG document lets us reuse those styles for multiple elements within the same document, but it prevents that CSS from being shared across multiple documents. That’s fine for logos and icons. But if you’re creating something like a library of chart styles, an external CSS file is a better bet.
Using a standard text editor, you can also add CSS to SVG images created with software such as Sketch, Inkscape, or Illustrator. Doing so won’t affect your ability to edit the image with the drawing application, but if you edit the file using image software, the application may rewrite or remove your CSS.
Linking from SVG to an External CSS File
As with HTML, linking to an external CSS file makes it possible to share styles across several SVG documents. To link an external CSS file, add to the beginning of your SVG file:


Using the Element
Alternatively, use the HTML element. If you do use this method, you’ll need to include the xmlns namespace attribute, as shown below:

Note: some older browsers need the element to be enclosed by or tags.
The element isn’t an SVG element. It belongs to HTML and XHTML. XHTML is a variant of HTML that’s parsed according to the rules of XML markup. According to the rules of XML, we can borrow elements and their behavior from other XML dialects, such as XHTML. To do so, however, we need to tell the browser which namespace the element belongs to using the xmlns attribute.
Using @import
We can also link to an external stylesheet by using @import inside

tags:

This method functions similarly to the method.
SVG and the Element: Limitations
Linking from SVG files to external assets, including CSS files, doesn’t work with the element. This is a security limitation of the element that’s baked into browsers.
If you’d like to use linked CSS with your SVG images, you’ll need to do either of these two things:
use the


Coordinate properties (x and y), center coordinate properties (cx and cy), and radius properties (rx, ry, and r), can be set using CSS. So can width and height. Units are optional for SVG attributes. CSS values, on the other hand, require units. Both lengths and percentages are valid for the properties mentioned here, but be aware that lengths work a bit differently with SVG documents. Remember that the S in SVG stands for scalable. The computed size of an SVG element also depends on:
the computed width and height of the root SVG element
the value of the root element’s viewBox attribute
any scaling transforms applied to the element or its ancestors
In other words, the corners of our element are (20, 50), (20, 320), (350, 320), and (20, 350) within the SVG coordinate system. However, the actual dimensions may be larger or smaller, depending on the factors above.
Not every SVG attribute is available via CSS — at least not in every browser. For example, Chrome and Edge support using the CSS path() function to set path data, or the d attribute:
path {
d: path("M 454.45223,559.21474 -304.96705,163.45948 417.4767,-296.33928 Z");
}

As of this writing, they are the only browsers that do. Work to add support in Firefox and WebKit has not yet begun.
For other shape elements, the SVG 2 specification is downright inconsistent. To date, you must use element attributes to set the properties of , , and elements.
That said, we aren’t limited to using type (or element) selectors to set properties. We could, for instance, define small, medium, and large circles using class selectors:

Regardless of the selector, using CSS syntax to specify properties also makes it easy to animate them. We’ll take a look at how to do this in the next section.
Animating and Transitioning SVG CSS Properties
Using CSS with SVG becomes more interesting when we add transitions and animations to the mix. The process is just like animating HTML elements with CSS, but with SVG-specific properties. Let’s create a twinkling star effect using the following SVG document:

Our document contains two star-shaped polygon elements, each with a class name of star. To create the twinkling effect, we’ll animate the first one. Here’s our CSS:
@keyframes twinkle {
from {
fill-opacity: .4;
}
to {
fill-opacity: 0;
transform: scale( 2 );
}
}
.star {
fill: rgb( 255,195,0 );
transform-origin: 50% 50%;
}
.twinkle {
animation: twinkle 1.5s infinite forwards ease-in;
}

Here we’ve used the SVG-specific property fill-opacity. As with CSS, if we can interpolate the value of an SVG styling property, we can animate or transition it. You can see two different points of the animation in the image below.

Let’s look at another example. This time we’ll create a drawing effect by transitioning the stroke-dasharray property. Here’s our SVG document:

The stroke-dasharray property accepts a comma-separated list of length or percentage values that create a dashed pattern. Odd-numbered values determine the dash length. Even-numbered values determine the gap length. A stroke-dasharray value of 5, 10 means that the stroke will be 5px long with a gap of 10px between each dash. A value of 5, 5, 10 alternates 5px and 10px dash lengths with 5px gaps in between.
We can use stroke-dasharray to create a drawing effect by starting with a zero dash length and a large gap, and ending with a large dash length and a dash gap of zero. Then we’ll transition between the two. Here’s what our CSS looks like:
circle {
transition: stroke-dasharray 1s ease-in;
fill: transparent;
stroke-dasharray: 0, 500;
}
.animate {
stroke-dasharray: 500, 0;
}

At the beginning of the transition, our stroke is invisible because the dash length is 0 and our gap is 500. But when we add the animate class to our circle, we shift the dash length to 500 and eliminate the gap. The effect is a bit like drawing a circle with a pair of compasses. Why 500? It’s the smallest value that worked to create this particular effect.
An Animated Path Future
Remember our example of defining a path via CSS from the previous section? Someday, we may be able to animate paths in every browser, using CSS:
path {
d: path("M357.5 451L506.889 192.25H208.111L357.5 451Z");
transition: d 1s ease-in-out;
}
.straighten {
d: path("M357.5 8871L406 -10113.75H208.111L357.5 351Z");
}

To date, however, only Chromium-based browsers such as Google Chrome and Microsoft Edge support animating path definitions in this way. To make this work in other browsers, use a JavaScript library such as GreenSock and its MorphSVGPlugin. In addition to its cross-browser compatibility, GreenSock and the MorphSVGPlugin also make it much easier to morph between two shapes regardless of the number of points in each.

With HTML documents, we might show, hide, or rearrange parts of the page based on the conditions of the viewport. If the browser window is 480 pixels wide, for example, we might shift our navigation from a horizontal one to a vertical, collapsible list. We can do something similar with media queries and SVG documents. Consider a logo, such as that of the fictitious Hexagon Web Design & Development pictured below.

Without media queries, this SVG logo would simply stretch or shrink to fit the viewport or its container. But with media queries, we can do more clever things.
Let’s distinguish between the HTML document viewport and the SVG document viewport. When SVG is inline, the HTML viewport and the SVG viewport are one and the same. The SVG document behaves like any other HTML element. On the other hand, when an SVG document is linked — as with the

As you may have noticed from looking at the image above, our SVG image retains its intrinsic dimensions even though part of it has been hidden. This, unfortunately, is a limitation of SVG. To fix it, we need to change the viewBox attribute of the SVG document, but only when the viewport is below a certain size. This is a great use case for matchMedia (which is discussed in Chapter 10, “Applying CSS Conditionally”).
The viewBox attribute, as its name suggests, determines the viewable area of an SVG element. By adjusting it, we can determine which part of an SVG image fills the viewport. What follows is an example using matchMedia and a media query to update the viewBox attribute:

Now, whenever the SVG container is 320 pixels or less, the value of viewBox will be "0 0 200 174". When it exceeds 320 pixels, viewBox gets restored to its initial value.

Since this technique uses either the onload event attribute or the SVGLoad event, it’s a good idea to embed our CSS and JavaScript within the SVG file. When CSS is external, the SVGLoad event may fire before its associated CSS finishes loading.
Using Media Queries with background-size
SVG documents and media queries aren’t limited to foreground images. We can also resize the SVG viewport using the CSS background-size property.
We’ll start with this SVG document:

This is a simple case. Our elements get a new fill color at specific viewport widths. When the viewport is 20 pixels wide, the fill value is teal. When it’s 300 pixels wide, it’s yellow.
To make this work, we have to use our SVG image as a background image and set the selector’s background-size property. In this case, we’ll use our image as a background for the element and for

  • elements:
    body, li {
    background: url(circles.svg);
    }
    body {
    background-color: #9c27b0;
    background-size: 300px auto;
    }
    li {
    background-position: left center;
    background-repeat: no-repeat;
    background-size: 1em auto;
    padding-left: 40px;
    font-size: 24px;
    margin: 1rem 0;
    }

    The result is pictured below.

    Conclusion
    Using SVG with CSS gives us more possibilities for flexible and adaptive documents. You should now know how to:
    use CSS to style SVG elements
    animate SVG properties
    employ CSS media queries and the matchMedia API to show and hide portions of an SVG document
    *      *      *
    This article is an extract from Tiffany’s book CSS Master, 3rd Edition. Check it out if you’d like to master other advanced CSS3 features like Flexbox and Grid. You can read it online, download the ebook, or get the hard copy!

    Coded at

  • Share your love

    Leave a Reply