Jeremy Wagner's

Web Development Blog

With occasional rambling diatribes about other stuff.

Cutting Cruft with an SVG Media Query

May 25, 2016

This isn't a huge success story, but I thought it was sufficiently spiffy to warrant a short post about an SVG media query that helped me to cut an unnecessary image from a client's website while still accommodating their design. Who knows? This short post may help you some day.

Not too long ago, I developed a static site for Weekly Timber & Pulp, a logging business in Central Wisconsin. The designer on the project whipped up some comps with two breakpoints: One for phones and tablets in portrait view, and another for tablets in landscape view and larger. The designer is a good friend of mine, and loves to throw me a curve ball every now and again. So he gave the site's logo a different treatment for each breakpoint.

The site logo appears on mobile in the upper left hand corner in white, and on desktop just above the navigation in green.
The site logo appears on mobile in the upper left hand corner in white, and on desktop just above the navigation in green.

As it tends to happen, I overlooked this detail until after the client approved the designs, so I was on the hook. Being borderline obsessive about website optimization, I knew I couldn't slap this together without thinking things over. I had two options. I could use two different images, which brought on slight discomfort.

I concur, Mr. Scott.
I concur, Mr. Scott.

Or I could do the sensible thing and find a way to get by with a single SVG image. The optimized and compressed version of the SVG is only about 17.3 KB, but duplicating an image is something you'd like to prevent if you can, right? What if you're still on an HTTP/1 server where requests aren't as cheap as they are on HTTP/2? What if your target audience is on a slower connection? It behooves us all to walk with care in situations such as these.

Thankfully, it dawned on me to use CSS in this SVG image. Because CSS is valid in SVG, that also means you can use media queries!

Wait, Media Queries in SVG?

SVG is XML, and while HTML isn't strictly XML, XML-derived schemas and HTML are all part of that soup. Hell, you can even inline SVG right into your HTML in most browsers.

Like HTML, SVG supports CSS. So unsurprisingly, media query support is a part of SVG. I learned this bit of trivia when I attended a conference some years ago. Of course, this nugget of information was filed away in the back of my brain, forgotten until such a scenario came where I could put it to use.

Thankfully, the only difference between the two logo treatments are that the colors are inverted. I opened the SVG in my text editor (and ran it through a pretty printer to restore the formatting lost to minification) and observed the following code near the top:


<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 824.7 318.9">
    <style type="text/css">
        .st0{
            fill: #fff;
        }

        .st1{
            fill: #197f21;
        }
    </style>

The relevant piece of code here is within the <style> tags. We have objects in the SVG that use one of two classes: Some that use the .st0, and some that use .st1. Those using .st0 are given a fill color of white (#fff), and those use .st1 are given a fill color of a sort of pine green (#197f21). This treatment looks like so:

The mobile logo treatment.
The mobile logo treatment.

So what we're grappling with here is a logo that's mostly white, but the tree on the right has a green stroke behind it to prevent it from bleeding into the rest of the logo. This is all well and good until you realize that this same logo has to exist on a white background when it hits the larger breakpoint. White on white just isn't going to work, so we need to use a media query to help us out.

How Media Queries Work in SVG

How media queries work in HTML documents is an easy concept to grasp: The browser window is a certain amount of pixels in width, and we specify some styles that take at and above (or below) a certain screen width.

CSS media queries in SVG work in the same way, but the threshold is determined differently than within an HTML document. When you specify a min-width or max-width media query for an SVG, it doesn't query the width of the browser, but rather the width of the element that contains the SVG. If you have an SVG referenced by an <img> tag and you want new styles to kick in when that <img> element is 300px or wider, you'd use this media query:


@media screen and (min-width: 300px){
    /* Your fancy new styles go here. */
}

The Weekly Timber logo grows to a maximum size of a little over 100px on the small breakpoint. Then it jumps to a fixed width of 340px on the large breakpoint. With this information, we can pick a reasonable middle point between the two, something like 300px. At this defined threshold, we then flip the fill colors with this code:


<style type="text/css">
    .st0{
        fill: #fff;
    }
    .st1{
        fill: #197f21;
    }

    @media screen and (min-width: 300px){
        .st0{
            fill: #197f21;
        }
        .st1{
            fill: #fff;
        }
    }
</style>

The new media query works in a mobile first fashion, since the site itself uses a mobile-first responsive design approach. For mobile devices, we have the white logo treatment. Then, when the logo width hits a width of 300px, we invert the color scheme for desktop devices.

To see the logo in action, head over to http://weeklytimber.com and resize the browser window. The logo treatment is the same image source (logo.svg) but the media query allows us to invert the fill colors, thus eliminating the need for a second image file. If you pull the logo up directly at http://weeklytimber.com/img/logo.svg, you can resize the browser window to see the color scheme flip at the 300px threshold.

Our single SVG image accommodating both logo treatments.
Our single SVG image accommodating both logo treatments.

That's it! Of course, this use case is very simple, and there's more capability in using media queries in your SVGs than just inverting fill colors. Experiment with CSS properties you know. See what works, see what doesn't, and always test across browsers.

For a deeper dive on CSS in your SVGs, check out this great article by Sara Soueidan on Smashing Magazine about styling and animating SVGs. There's a lot more under the hood than the example shown in this post.

Cheers,
-j

Thoughts? Let's hear them!