By Craig Buckler

CSS3 Gems: The calc() Function

By Craig Buckler

There are many hidden gems in the modular CSS3 specifications. In this post we’ll look at calc(); an incredibly useful property which may change the way you approach layout design.

The CSS3 calc() function is primarily used to calculate lengths, numbers, angles, transition/animation times or sound frequencies. However, it allows you to mix measurement types — a powerful concept in CSS.

Consider a website layout containing two floated elements. You want both elements to be an equal width separated by a 60px horizontal margin. Sounds easy? It’s not a problem in fixed-width design; if the page width is 960px, both elements will be 450px.

But what about fluid or responsive layouts? It’s not possible to determine the page width so most developers would set each element to, say, 45%. The 10% margin will only be 60px if the page happens to be 600px; a wider or narrower browser window will enlarge or contract the margin accordingly.

Fortunately, the new calc() function allows us to calculate widths. In this case, we want both elements to be 50% minus 30px, e.g.

#element1, #element2 { 
  float: left;
  width: calc(50% - 30px);

#element2 { 
  margin-left: 60px;

Perhaps you want a margin which is relative to the font size — such as 4em? No problem:

#element1, #element2 {
  width: calc(50% - 2em);

Or maybe you want a 2px border around both elements:

#element1, #element2 { 
  width: calc(50% - 2em - 4px);
  border: 2px solid #000;

I recommend you keep calculations simple, but it’s possible to use complex formulas, e.g.

 #element1, #element2 { width: calc((50% + 2em)/2 + 14px); } 

Browser Support

The calc() function is a W3C recommendation so guess which browser offers native support?

You’re wrong. At the time of writing, it’s just Internet Explorer 9. Firefox also supports it with a prefix; -moz-calc(). It’s not been implemented in webkit (Chrome and Safari) or Opera yet but, it’s so useful, I suspect we won’t need to wait long.

Fortunately, you can use progressive enhancement in your stylesheets:

#element1, #element2 {
  width: 45%; /* all browsers */
  width: -moz-calc(50% - 30px); /* Firefox 4+ */
  width: calc(50% - 30px); /* IE9+ and future browsers */

Remember that you’d also need to adjust margins accordingly, e.g.

#element2 {
  margin-left: 10%; /* all browsers */
  margin-left: -moz-calc(60px); /* Firefox 4+ */
  margin-left: calc(60px); /* IE9+ and future browsers */

CSS3 min() and max()

If you like calc(), you’ll love the min() and max() functions. They accept two or more comma-separated values and return the minimum or maximum accordingly, e.g.

#myelement {
  width: max(300px, 30%, 30em);
  font-size: min(10px, 0.6em);

The functions will be especially useful when using relative font sizes to ensure text does not become too large or small.

Unfortunately, min() and max() are not currently supported in any of the latest browsers. Let’s hope they appear soon.

  • min() and max() looks incredibly usefull, but are they only in the standard, so far (as you say they are not supported by any browsers)?

    Will they also support references to other elements, like width: min(#element1.width, #element2.width) ?

    Yes, I’m making a wish-list here ;)

    • min() and max() are in the W3C specification so they must have been proposed by at least one vendor. Perhaps they’re available in a beta somewhere?

      I don’t think you’ll be able to pass elements as dimension values but you can pass calc() results, e.g. min(calc(100%-50px), calc(100%-2em+1px)). With a little careful planning, those calculations could be equivalent to an element’s dimensions.

    • Yeah I have always wanted this. Would be great to calculate widths of elements!

  • Yes the cal() function is seriously sexy, been waiting for this for a long time and it’s so bloody handy. Hopefully Chrome and Opera will catch up. Thanks for the article!

  • This is a great little gem. I can’t wait until it is 100% cross-browers…well…the good browsers at least.

  • Artful Dodger

    Wow! This looks extremely useful. Designing websites with fluid designs is gonna be so much easier now. I think I’ll refrain from using it until most of the main browsers support it though or at least the Webkit browsers.

  • Seems to spit in the face of the separation of responsibilities. I know I can’t be the only one around here who thinks the new spec is beginning to gray the area(s) between the presentation and mechanical layers… Old news, I’m sure.

    In any event, this will open up an entirely new world for UI. Geez, think of the possibilities!

    • It’s been happening for a while. I was initially uncomfortable with transitions and animations but I’ve come round to the idea because they’re presentational.

      While calc() is an obvious programming construct and feels a little odd in CSS, it’ll only affect the presentation of element dimensions, angles etc. And it’ll solve numerous layout problems we’ve all encountered.

    • Chris Emerson

      It’s this kind of thinking and over-zealous application of separation of principles that really holds things back unfortunately. Why is calculating what a margin or other property of an element should be nothing to do with presentation? I do this maths in my head all the time to work out what the CSS should be, why not make it easier by having the browser do the donkey work for you?

      There are many things it would be pretty useful to have in CSS that we currently don’t have – regular expression matching (with back-references), many of the things that some off the CSS pre-processors give you (variables spring to mind), yet someone always seems to spring up and claim (wrongly) that it breaks the principle of separation of concerns. We aren’t going to make much progress on the web if people continually hold things back like this!

      • I agree these discussions often go a little too far. In the same way, pedantic semantic purists can argue for days about whether an HTML5 article or section is more appropriate for specific content. Ultimately, few people care – just pick one and get the job done.

        I can understand Wolf’s point of view, though. CSS is moving beyond markup presentation into the realms of a programming language. In many ways that’s good – I would be the first to welcome variables which allowed color naming. But does it blur the distinction between the disciplines and technologies? That may not be for the best – especially if you remember the early days of web development when everything was an intermingled unmaintainable mess.

        That said, I’m certainly using calc()!

    • Agreed that it’s a bit discomfiting, but at least it’s still presentation-related.

      That calc() function will be fantastic! :D

  • Great Article, looking forward to these functions becoming more widely available.

    Do you know if there is a function which would allow you to set equal heights for divs, so
    if you have 3 columns with different lengths of content and you wanted them to all have the height of the tallest one. Rather than setting the height to a fixed size it would be great if you could set the height relative to the other columns.

    • I don’t think you’d use a function for that, but CSS columns and the new template layout module will help enormously.

  • Chris Roberts

    In my opinion the addition of programming-esque syntax into CSS doesn’t render it’s job as a presentational device null (no pun intended). It’s what the language accomplishes, not necessarily the way it accomplishes it that is important. Calculating margins or anything else calc() would allow use to in CSS is fine becuase expressing dimensions of an element is what CSS is for whether it’s pixels, ems, percentage, or the result of a calculation.

    That being said, I do agree with in regards to animations and transitions.

  • ed

    Great and useful functions. I am still puzzled by the prefixes in Mozilla (and other browsers). If they want to implement ‘calc’ why not just call it ‘calc’. Why on earth does it have to be ‘moz-calc’

    • The vendor prefixes solve the problems caused by draft specifications. If the spec changed, you could have two versions of Firefox with differing calc() functions. That said, calc() seems to be fairly simple and Microsoft were happy to add it without a prefix (possibly because they proposed it).

  • Would you know of an example website with these functions in action?

    • No – yours could be one of the first!

      Seriously, though, few people would notice it in action. I suspect few designers will use it until it has better cross-browser support, but there’s no reason why you can’t adopt it today.

  • Nikola

    Great write up, this is a dream come true for many of us!

  • Robert O’Callahan

    IE9 should have prefixed calc() but didn’t. At the time they shipped there were still a lot of unresolved issues in the spec, and some of them are still unresolved. For example, it was unclear how a “0” without units should be treated in a calc() expression, it was unclear how unit mismatch errors should be treated, it was unclear how division by an expression that evaluates to zero should be treated.

Get the latest in Front-end, once a week, for free.