Thursday, 13 September, 2018 UTC

Summary

The following is a short extract from Tiffany's upcoming book, CSS Master, 2nd Edition, which will be available shortly.

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 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 object or img elements—we’re dealing with the SVG document viewport.

Media queries work in both cases, but when the SVG document is linked, its viewport is independent of its HTML document. In that case, the size of the browser window doesn’t determine the size of the SVG viewport. Instead, the viewport size is determined by the dimensions of the object, iframe, or img element. Take the (abridged) SVG document that follows as an example:[^4]

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.

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:

Note: Browsers are a little bit of a mess when it comes to handling the SVGLoad event. In my tests, addEventListener worked most consistently with Firefox. For best results in Chrome and Safari, use the onload event attribute. Microsoft Edge also works best with onload, but only when used as an attribute of the <svg> tag. In other words, <svg onload="updateViewBox">.

Now, whenever the SVG container is 20em or less, the value of viewBox will be "0 0 200 174". When it exceeds 20em, viewBox will be restored to its initial value as represented below.

Note: For a fuller primer on creating interactive SVG documents, read the “Dynamic SVG and JavaScript” chapter of An SVG Primer for Today’s Browsers from the W3C.

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.