Media queries and calc

calc isn’t a new feature, but at the time of writing MDN describes it as experimental:

this technology’s specification has not stabilized, check the compatibility table for the proper prefixes to use in various browsers. Also note that the syntax and behavior of an experimental technology is subject to change in future versions of browsers

MDN

According to caniuse.com, it’s a little safer than MDN suggests.

One area where it does fall over is media queries. For a number of reasons, it’s better practice to use proportional media queries (em) than pixel based media queries.

This falls over with range based media queries, consider the following:

@media (min-width:64px) and (max-width:127px) {
  /* two cells/row */
  .grid-cell:nth-child(2n+1) { clear: left; }
}

@media (min-width:128px) {
  /* three cells/row */
  .grid-cell:nth-child(3n+1) { clear: left; }
}

calc becomes necessary when converting this exactly to proportional based media queries:

@media (min-width:4em) and (max-width:calc(8em - 1px)) {
  /* two cells/row */
  .grid-cell:nth-child(2n+1) { clear: left; }
}

@media (min-width:8em) {
  /* three cells/row */
  .grid-cell:nth-child(3n+1) { clear: left; }
}

As far as I am concerned, the above code demonstrates why calc is one of modern CSS’s most elegant features. You can have your animations, your gradients, your rounded corners. I will take calc.

Unfortunately it doesn’t work in media queries*.

Options for calc-less media queries

Hoping browsers round down and using @media (min-width:4em) and (max-width:59.99em).

Hoping browsers include media queries in zoom calculations and using pixel based values. Not including them started as a bug, in up-to-date browsers it is squashed.

Hoping reverting the value in this code block won’t cause unforeseen interference with other code.

@media (min-width:4em) {
  /* two cells/row */
  .grid-cell:nth-child(2n+1) { clear: left; }
}

@media (min-width:8em) {
  /* three cells/row */
  .grid-cell:nth-child(2n+1) { clear: none; }
  .grid-cell:nth-child(3n+1) { clear: left; }
}

Regardless, there is some amount of hope involved. Fortunately, the amount of hope in web development is in sharp decline, I’m sure it won’t be too long before the above is resolved.

*Checked Jan 20, 2015 against Chrome 39, Firefox 34 & Safari 8 on OSX

Published
Categorized as Code Tagged

By Peter Wilson

Peter has worked on the web for twenty years on everything from table based layouts in the 90s to enterprise grade CMS development. Peter’s a big fan of musical theatre and often encourages his industry colleagues to join him for a show or two in New York or in the West End.

1 comment

  1. Peter, I hate that we have to deal with this, but we do. :(

    I use Sass, so I use a couple of different solutions, depending on the project:

    1. Using variables for em values:
    $midBp: 45em;
    $midBpLess: 44.9375em;
    (why that value for BpLess? 1px/16 of 1em is .0625em)
    Then you can use the mediaquery:
    @media only screen and (min-width: #{$midBp}) {}
    @media only screen and (max-width: #{$midBpLess}) {}
    and you have no issue with browsers rounding incorrectly, which they’ve been known to do.

    2. Using Sass’s arithmetic.
    Writing this mediaquery:
    @media only screen and (min-width: (767em/16)) {}
    @media only screen and (min-width: (768em/16)) {}
    results in:
    @media only screen and (min-width: 47.9375em) {}
    @media only screen and (min-width: 48em) {}

    Both are great techniques for covering the edge cases you’re talking about here.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.