Coding Q&A With Chris Coyier: Responsive Sprites And Media Query Efficiency

Advertisement

Howdy, folks! Welcome to more Smashing Magazine CSS Q&A. It works like this: you send in questions you have about CSS, and at least once a month we’ll pick out the best questions and answer them so that everyone can benefit from the exchange. Your question could be about a very specific problem you’re having, or it could even be a question about a philosophical approach. We’ll take all kinds.

If you’re interested in exploring more Q&A, there’s a bunch more in my author archive.

Resolution Aware Sprites

Joshua Bullock asks:

Your last round of questions was titled “Box-Sizing And CSS Sprites” which offered some great answers for two separate items, but didn’t take them that one step further for responsive design. Ultimately, my question is this: Is there a preferred/suggested way of handling responsive sprites at all for multiple resolutions and image scaling? Is this even possible?

This is a hot topic lately because of the rise in “retina” displays. But really, this problem has been building up for a while. Us Web designers often work in “pixels”, for instance, setting the width of an image: img { width: 100px; }. But what is 100px? It’s been a long time since that literally referenced a pixel on the screen. These days it’s a rather arbitrary measurement. 100px ends up being around an inch on a physical screen, regardless of its resolution.

Retina displays made a really quick and big jump in resolution. Apple’s 27″ Thunderbolt Cinema display has 109 PPI (pixels per inch) while the 15″ Retina MacBook has 220 PPI (literally twice as dense) meaning there are more pixels on the drastically smaller screen.

If you are drawing a solid red box on the screen, no problem at all! The higher resolution display will simply draw it with more pixels. But what about a little icon that you designed at 16×16 “pixels” in Photoshop? Both a high-resolution display and low-resolution display need to display that icon at the same physical size, but the high-resolution display needs to essentially fake a lot of those pixels. It’s like when you enlarge a photo in Photoshop, it immediately starts looking like crap.

One solution is to make all your original images bigger. Instead of a 16×16 “pixel” image, you can actually make it 32×32 in Photoshop but have CSS size it to 16×16. Then the information is there for the high-resolution display.

Your question was explicitly about sprites. How can we make a sprite image that is twice the size for retina screens without making it a huge pain in the butt? Fortunately, Maykel Loomans recently published a very simple and clever technique for this.

Essentially, you make the sprite exactly (and literally) twice as big, while maintaining its proportions. Then in your “normal” CSS, you load up the “normal” sprite and do all the background-position and sizing stuff to make your sprite work. Then using media queries, you overwrite the background-image with your new retina sprite (when the conditions are correct). You use background-size to shrink the retina sprite, so you don’t have to touch the tedious positioning/sizing stuff. Yay!

span.rss-icon {
   /* Size of sprite image is 200px ✕ 200px */
   background: url(sprite-1x.png)  72px 181px;
   width: 16px;
   height: 16px;
}

@media
  (min--moz-device-pixel-ratio: 2),
  (-o-min-device-pixel-ratio: 2/1),
  (-webkit-min-device-pixel-ratio: 2),
  (min-device-pixel-ratio: 2) {

  span.rss-icon {
    /* Size of retina sprite image is 400px ✕ 400px */
    background-image: url(sprite-2x.png);
    /* Bring down size to 1x size */
    background-size: 200px 200px;
  }

}

Here’s a demo of that.

Liquid — Fixed — Liquid

Niels Matthijs asks:

The layout I’m trying to create is L1F2L3, meaning the first and third column are both liquid, while the center column is fixed. I’ve been trying some stuff out, and even though I came close a couple of times, the solution never really pleased me. Do you have anything on this?

The Flexbox method in CSS can hook you up with this solution, and it’s pretty easy:

<div class="grid">
  <div class="col fluid">
    ...
  </div>
  <div class="col fixed">
    ...
  </div>
  <div class="col fluid">
    ...
  </div>
</div>
.grid {
  display: -webkit-flex;
  display: flex;
}
.col {
  padding: 30px;
}
.fluid {
  flex: 1;
}
.fixed {
  width: 400px;
}

Flexbox

See demo. I’m hesitant to recommend this as a “real world” solution because the spec for flexbox has changed rather dramatically recently. The code above is the newer syntax which is supported only by Chrome 21+ at the time of this writing (see support charts). There is an older syntax (see demo) that has wider browser support, but will probably someday stop working.

If you are in a position where you know that the middle column will be the longest, you could have the parent container have percentage padding on the right and left sides and absolutely position the left and right columns within it (at the width of that percentage). And if you don’t know that, you could always measure the three columns with JavaScript, and set the parent container’s height to the tallest of the three.

The New

Peter Karlstein asks:

What are the most useful CSS tips, techniques, tricks that you’ve learned recently? Can you present a couple of your recent “Aha!” moments with CSS?

Messing around with the latest flexbox stuff (as I did above) was pretty fun, although not really useful quite yet.

In the past few months I’ve moved entirely to using Compass, which has been tremendously useful. Over time I’ve grown tired of the repetitive and finicky things in CSS. But Sass and Compass make authoring CSS fun again for me.

As far as little CSS “tricks”, I’ve had to use this one several times lately. Essentially, if somehow some super long string of text gets into a container with no spaces, it will break out of the container in a super awkward overlapping fashion. This is most common with user-generated content and users pasting in URL’s. I like applying this class to any user-generated text containers:

.prevent-text-breakouts {
  -ms-word-break: break-all;
      word-break: break-all;
      word-break: break-word;
  -webkit-hyphens: auto;
     -moz-hyphens: auto;
          hyphens: auto;
}

Before:

Long strings of text breaking out of the container.

After:

Long strings of text fixed.

Also, Uncle Dave’s Ol’ Padded Box is a good one to have in your toolbox.

Relative Font Sizing

Greg Nelson asks:

Do you think there will one day (hopefuly soon) be a way to set a font-size to be in direct relationship to the width of it’s parent element, or some other truly responsive measure? e.g. <p> font size could be a percentage of the width of a sidebar div it sits inside of, so that as screen width’s change (and width of sidebar changes, if it’s also a percentage of <body> width), the size of the font will change too?

Yep, that’s coming! You’ll be able to set font-size with vw and vh units. Those stand for “viewport width” and “viewport height”. 1vw = 1% of the current browser window’s width. Here’s the CSS spec for that. And here’s a tutorial on using them. This is how it will work:

At the time of writing this, there is only support in Chrome 20+ and IE 10. If you need full browser support now (and don’t mind using a bit of JavaScript), you can use FitText.js (best for headers only).

FitText

Media Query Efficiency

Mark Roland asks:

When organizing media queries in a CSS file, is there any advantage or disadvantage to how they are grouped?

For instance, is there a browser performance difference between using several media query blocks (e.g. “@media screen and (max-width: 480px) { }” ) so that element styles are defined together (header, nav, footer, etc.) versus placing all of the element styles for the specific media query into one single media query block?

The former allows for easier development, but costs increased file size. Are there browser rendering costs for redundant media queries?

Technically, probably yes. The worst offense is the extra file-size that it causes. Using one is clearly less text than using multiple. But the fact is if you gzip/deflate content (you probably are), that will eat that repetitive code for breakfast and it won’t even increase file-size too much. As far as CSS parsing time, that stuff happens so fast that you really don’t need to think about it.

So on a practical level: don’t worry about it. If you have some time to spend on making your website faster, losslessly optimizing your images will make a way bigger difference.

ImageOptim

If anyone is confused on why Mark is asking this, it’s most likely because of the abilility that Sass and LESS have to “nest” media queries (see). This is a really neat feature that makes working with media queries a lot more clean an intuitive, as you the author. However, the final output results in many duplicated media queries. I know that addressing this issue is on the mind of the lead developer from Sass.

Onward!

Keep up the great questions, folks! Got a good one? Send it in, and we’ll be picking the best ones for the next edition.

Image source of picture on front page.

CSS,

↑ Back to top

I create websites and help others create better websites through writing and speaking. I consider myself a lucky man for getting to work in such a fun and rewarding field.

  1. 1

    I’m pretty certain that when using a retina image you still keep background-size: 100%; because it’s about being 100% of the size of the container, not about being 50% of the original image size.

    0
    • 2

      Yep, that’s right; I still miss a method of resizing the background image relative to it’s original size (i.e. with unitless values as you do in line-height)

      0
    • 3

      Indeed that is correct, I’ll make sure the article is fixed to be more correct. The percentage in background-size refers to the size of the element, not the size of the background-image, which I think is easy to confuse.

      I think the best way to handle that is to just use pixel values to be sure. So the @1x sprite is 200px ✕ 200px, you’d make a @2x sprite at 400px ✕ 400px, then set the background-size explicitly to background-size: 200px 200px;

      Here’s a demo of that working: http://codepen.io/chriscoyier/pen/IadqD

      0
      • 4

        What i am concerned about, when i see an approach like that is always bandwidth.
        Because larger Sprites / Sprites with a higher resolution tend to have bigger file sizes and as such use more bandwidth.

        At least in the country i live in, most of the mobile web contracts infact do limit the speed after a certain amount of bandwidth hase been used during that month. So i’d be curious about a way, that takes usage of bandwidth into consideration.

        0
        • 5

          I’ve moved away from sprites for many uses and towards font-based solutions, like Font Awesome and Zurb’s icon set. These have great backwards compatibility (at least to IE8), are vector-based, and easily configured via CSS (it’s a font, after all). They’ve even taken it beyond font-based icons and into SVG.

          Bitmap-based sprites are just too much of a hassle, and if I can make a vector-based icon work, I’ll chase that every time.

          0
  2. 6

    Yum! Thanks. Want more :)

    0
  3. 7

    Regarding media query performance and selector optimization, it’s good to know, but probably nowhere near first on most peoples’ list of performance issues. To quote:

    you are not allowed to care about the performance of [selectors] until you concatenate all your javascript, have it at the bottom, minify your css and js, gzip all your assets, and losslessly compress all your images. If you aren’t getting 90+ Page Speed scores, it’s way too early to be thinking about selector optimization.

    0
    • 8

      The author may have hinted at this in the article, but using Compass to compile your CSS gets you a lot of optimization (when you want it).

      Rabbit trail: which is more performant, Compass/SASS or LESS? The idea of doing what SASS does on my computer in the browser (or even on the server) with Javascript (Less.js) gives me a shudder. Opinions? Benchmarks?

      0
  4. 9

    Hi Chris

    I’d be curious to know what you think about this:

    http://chiefalchemist.com/responsive-css-sprites-proof-of-concept-v0-1-0/

    0
  5. 10

    Hi Chris, I was wondering if there is any platform on windows that you would suggest for lossless image compression. I checked the one you mentioned (imageOptim), but its just for mac.

    question-2: I know we can put ‘max-width’ for images and that makes them responsive. Is there a way to do the same for slideshows as well?

    0
  6. 11

    Retina display sprites seem to me a little awkward.
    I mean, who knows what the resolution of next generation devices would be like?
    Wouldn’t it be preferable to use svg sprites and not worry about pixels? That’s what I’ve done in my website to make it retina ready. The png sprites could be used as a fallback for ie8 via modernizr

    0
    • 12

      I agree. SVG images are a better solution because they are rasterized at the display resolution. Also, “Retina” displays are not the only reason to use SVGs. SVGs allow your website to scale without getting blurry when use the zoom feature of their desktop or mobile browser, and it provides a much more general solution than just supporting Apple’s brand of pixel doubling.

      0
    • 13
  7. 14

    tomasz stryjewski

    August 14, 2012 12:29 am

    @flex box – why not to use display:table | table-row | table-cell to do the flex thingy?
    except for having 1 more depth level, it works with every “modern browser” ( check http://jsfiddle.net/stryju/sUV7G/ )

    0
  8. 15

    Elco Brouwer Von Gonzenbach

    August 14, 2012 12:58 am

    Re. relative font sizing: I’ve been toying around with a very simple bit of Javascript that relates the body’s base font size to browser window width. When used with CSS that’s completely related to base font size, the whole layout scales with the window, leaving all proportions intact. Haven’t used it in any production environment yet, so it’s still a quick and dirty fix:

    <script type="text/javascript">
    function doResize() {
    	// do not scale below certain window size
    	if(parseFloat(window.innerWidth) > 768){
    		newSize = Math.round(parseFloat(window.innerWidth) * (17*100/1200)*(100/16))/100;
    		if(newSize <= 106.25) {
    			document.body.style.fontSize = newSize +  "%";
    			document.getElementById("heading").innerHTML = "Font-size: " + newSize + "%<br />Window: " + window.innerWidth;
    		}
    		else {
    			document.body.style.fontSize = "106.25%";
    			document.getElementById("heading").innerHTML = "Font-size: 106.25%<br />Window: " + window.innerWidth;
    		}
    	}
    }
    window.onload = doResize;
    window.onresize = doResize;
    </script>
    

    Tested so far in Safari 5, Chrome 20 and Firefox 14 on a Mac.

    0
  9. 16

    Regarding the question about ‘Liquid — Fixed — Liquid’, there’s an easy solution that doesn’t have to rely on JavaScript or experimental, barely-supported techniques. Using a dash of ‘display:table’ forces the columns to be equal height and makes it super-easy to mix any combination of fixed and flexible columns. (Or even ‘elastic’ %-based columns!)

    I’ve thrown up a quick demo at http://lab.intangiblestyle.com/demos/flex-fix-flex-eqheight to show it in action.

    0
  10. 17

    I want to offer alternative answer to Niels Matthijs question about Fluid – Fixed – Fluid Layout:

    The solution is based on my Two Lines CSS Framework – http://www.vcarrer.com/2010/10/two-lines-css-framework.html

    The code:

    .row { display:table; width:100% }
    .cell { display:table-cell; vertical-align:top; padding-left:10px }

    Demo: https://dl.dropbox.com/u/2111778/Fluid-Fixed-Fluid.html

    This solution doesn’t work in IE6/7. But it will work in IE8 and all other modern browsers.

    0
  11. 18

    The behavior of page-wide relative font-sizing can be simulated using media queries. It isn’t as fluid as the new units but its a relatively painless drop-in solution that gzips down to nothing.

    http://jsfiddle.net/bnickel/WQ7gf/
    http://jsfiddle.net/bnickel/WQ7gf/show

    0
  12. 19

    Regarding the sprite example. Whenever you override an image with another image in CSS, both images get downloaded. Is there really not a better way? At least you’re loading the smaller one first, but if you’re pulling the larger one at all, then there’s a solid chance they’re on a mobile device when bandwidth matters most.

    I guess you could include a media query checking for a pixel ratio of 1 for the lower-res stuff.

    0
  13. 20

    This may be a non relative question and sorry for sounding/asking such a silly question but how does an intermediate developer such as myself who only does HTML/CSS and uses jQuery plugins not get overwhelmed with all the new things constantly being popularized and used these days? From gzipping and minifying CSS to using github/codepen/sass and optimizing for all the new resolutions/screen sizes with media queries while implementing best practice techniques which seem to be changing at such a rapid pace?

    Again sorry for sounding like such a noob and asking such a broad question but I constantly find myself drowning in information on the best way to do this or to do that without ever knowing what is the best way to achieve best practices in site development and execution.

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top