meyerweb.com

Skip to: site navigation/presentation
Skip to: Thoughts From Eric

Whitespace in CSS Calculations

I’ve been messing around with native calculated values in CSS, and there’s something a bit surprising buried in the value format.  To quote the CSS3 Values and Units specification:

Note that the grammar requires spaces around binary ‘+’ and ‘-’ operators. The ‘*’ and ‘/’ operators do not require spaces.

In other words, two out of four calculation operators require whitespace around them, and for the other two it doesn’t matter.  Nothing like consistency, eh?

This is why you see examples like this:

width: calc(100%/3 - 2*1em - 2*1px);

That’s actually the minimum number of characters you need to write that particular expression, so far as I can tell.  Given the grammar requirements, you could legitimately rewrite that example like so:

width: calc(100% / 3 - 2 * 1em - 2 * 1px);

…but not like so:

width: calc(100%/3-2*1em-2*1px);

The removal of the spaces around the ‘-’ operators means the whole value is invalid, and will be discarded outright by browsers.

We can of course say that this last example is kind of unreadable and so it’s better to have the spaces in there, but the part that trips me up is the general inconsistency in whitespace requirements.  There are apparently very good reasons, or at least very historical reasons, why the spaces around ‘+’ and ‘-’ are necessary.  In which case, I personally would have required spaces around all the operators, just to keep things consistent.  But maybe that’s just me.

Regardless, this is something to keep in mind as we move forward into an era of wider browser support for calc().

Oh, and by the way, the specification also says:

The ‘calc()’ expression represents the result of the mathematical calculation it contains, using standard operator precedence rules.

Unfortunately, the specification doesn’t seem to actually define these “standard operator precedence rules”.  This makes for some interesting ambiguities because, as with most standards, there are so many to choose from.  For example, 3em / 2 * 3 could be “three em divided by two, with the result multiplied by three” (thus 4.5em) or “three em divided by six” (thus 0.5em), depending on whether you privilege multipliers over dividers or vice versa.

I’ve looked around the Values and Units specification but haven’t found any text defining the actual rules of precedence, so I’m going to assume US rules (which would yield 4.5em) unless proven otherwise.  Initial testing seems to bear this out, but not every browser line supports these sorts of expressions yet, so there’s still plenty of time for them to introduce inconsistencies.  If you want to be clear about how you want your operators to be resolved, use parentheses: they trump all.  If you want to be sure 3em / 2 * 3 resolves to 4.5em, then write it (3em / 2) * 3, or (3em/2)*3 if you care to use inconsistent whitespacing.

18 Responses»

    • #1
    • Comment
    • Tue 10 Apr 2012
    • 1104
    Dan wrote in to say...

    Good research, Eric! I hadn’t heard that expressions like this were a part of general CSS (since I’ve been focused on SCSS so much).

    • #2
    • Comment
    • Tue 10 Apr 2012
    • 1129
    Bouke wrote in to say...

    Eric, nice article but I cannot agree with you on the mathematics. The article on Wikipedia you linked to states this:

    The order of operations, or precedence, used throughout mathematics, science, technology and many computer programming languages is expressed here:[2]
    * terms inside parentheses or brackets
    * exponents and roots
    * multiplication and division
    * addition and subtraction

    And also this:
    These mnemonics may be misleading when written this way, especially if the user is not aware that multiplication and division are of equal precedence, as are addition and subtraction. Using any of the above rules in the order “addition first, subtraction afterward” would also give the wrong answer.

    So 3em / 2 * 3 equals 4.5em as multiplication and division are of equal precedence; thus should be read from left-to-right. If you multiply first, you are reading from right-to-left and disregard the equality precedence.

    • #3
    • Comment
    • Tue 10 Apr 2012
    • 1130
    Rainer wrote in to say...

    This is just my opinion, but I think the whitespace around the + and – operators as seen in your example above makes the order of operations much more readable. Should it be required? Maybe not. Could it be a best practice? Maybe so.

    • #4
    • Comment
    • Tue 10 Apr 2012
    • 1132
    Brian Dukes wrote in to say...

    I’m not seeing any browser doing the multiplication before the division in that scenario. As the article you link to explains, division and multiplication have the same precedence (hence the differing mneumonics), as do addition and subtraction. They’re just evaluated left to right.

    In Chrome (Canary), Firefox, and IE 9, this test fiddle (http://jsfiddle.net/bdukes/KfL7a/2/) shows the calculation being left to right without inconsistency.

    Great to understand the spacing inconsistency, I’m sure that’ll trip up a lot of people (definitely something for CSS minifiers/processors to understand)

    • #5
    • Comment
    • Tue 10 Apr 2012
    • 1133
    Chapel wrote in to say...

    I think the first example expression is MUCH easier to read (since you have to adhere to the order of operations). Your last two examples just make my eyes cross and do weird things.

    That being said, I fully agree that consistency (especially when writing up specs people have to adhere to) is key, and there’s absolutely no reason why the last example should barf and break everything.

    • #6
    • Comment
    • Tue 10 Apr 2012
    • 1201
    ben wrote in to say...

    The implication is that infix notation is assumed, but… not documented?

    • #7
    • Comment
    • Tue 10 Apr 2012
    • 1210
    Boris wrote in to say...

    Eric, the standard order of operations rules, both in the US and everywhere that mathematics is taught, are that * and / have the same precedence and you evaluate them left to right. The wikipedia page you link to clearly describes this. The particular section you linked to isn’t about different “standards”. It’s about different _mnemonics_ (some incorrect) that people try to use to remember the order.

    So your example should end up with 4.5em. That’s what Gecko does, certainly. Which browser did 0.5em in your testing?

    That all said, I agree that using parentheses to disambiguate expressions like this is absolutely the right thing for human-readability, precisely because most people don’t actually remember their order of operations very well.

    • #8
    • Comment
    • Tue 10 Apr 2012
    • 1252
    Eric Meyer wrote in to say...

    Sorry, Boris, Brian, and Bouke—that was a typo which I’ve now fixed: I was sure I’d mistakenly switch up 0.5em and 4.5 em, and so I did. Next time I need to build an example that yields wildly different results so there’s less chance of a mistake.

    As for the difference between standards and mnemonics, well, if someone learns a mnemonic they regard it as a standard. Learn the wrong mnemonic, learn the wrong standard. I still say the specification should state explicitly which ordering precedence it follows just so there’s less chance of mistake.

    I sense a theme…

    • #9
    • Comment
    • Tue 10 Apr 2012
    • 1253
    tom jones wrote in to say...

    yeah, what Boris said.

    “depending on whether you privilege multipliers over dividers or vice versa.”

    no, no (sane) system prioritizes multiplying over dividing (or vice versa). it’s always in the order it’s written (unless it’s polish/reverse-polish/postfix/.. notation).

    • #10
    • Comment
    • Tue 10 Apr 2012
    • 1311
    Chris Neale wrote in to say...

    So, on which day are we celebrating Bidmas this year?

    • #11
    • Comment
    • Tue 10 Apr 2012
    • 1419
    Eric Meyer wrote in to say...

    I’m open to any reasonable suggestions, Chris! Regardless of date, though, I think the celebrations have to be held on eBay.

    • #12
    • Comment
    • Tue 10 Apr 2012
    • 1853
    J. King wrote in to say...

    I would imagine that The spaces around adition and division are required because of the grammar defining values. Whereas “2em/2″ is unambigously a division operation, “4em-2em” presumably looks like “(4em)(missing operand)(-2em)”. I agree it’s a -little- stupid, but presumably there was a very, very good reason not to complicate the grammar to make this more intuitive for minimalists. For what it’s worth I agree that all operations should consistently require spaces instead.

    • #13
    • Comment
    • Tue 10 Apr 2012
    • 1917
    J. King wrote in to say...

    Oops. That should have read “(missing operator)”, of course…

    • #14
    • Comment
    • Tue 10 Apr 2012
    • 1958
    Boris wrote in to say...

    J. King, you’re right in general, but to a CSS parser your example looks like the number “4″ followed by the unknown unit “em-2em”. The relevant parts of the CSS tokenizer spec:

    DIMENSION {num}{ident}
    ident [-]?{nmstart}{nmchar}*
    nmstart [_a-z]|{nonascii}|{escape}
    nmchar [_a-z0-9-]|{nonascii}|{escape}

    so “em-2em” is a perfectly valid “ident” and the whole thing is a single DIMENSION token as far as the tokenizer is concerned. Then the parser sitting on top of the tokenizer has to drop the whole thing because the actual ident is not a known unit, but making that somehow work would require completely redefining how CSS parsing works…

    • #15
    • Pingback
    • Wed 11 Apr 2012
    • 0909
    Received from Dew Drop – April 11, 2012 (#1,304) | Alvin Ashcraft's Morning Dew

    [...] Whitespace in CSS Calculations (Eric Meyer) [...]

    • #16
    • Pingback
    • Fri 13 Apr 2012
    • 0225
    Received from Some links for light reading (13/4/12) | Max Design

    [...] Whitespace in CSS Calculations [...]

    • #17
    • Comment
    • Sun 15 Apr 2012
    • 1557
    Doug wrote in to say...

    I’ve been looking for a standards-based way to do stuff like this since way back in the days of IE-only “behaviors,” but I can’t get FF, Chrome or IE9 to recognize calc. What browsers support this?

    • #18
    • Comment
    • Sun 15 Apr 2012
    • 2112
    Boris wrote in to say...

    Doug, Firefox supports calc() with a “-moz” prefix. IE9 supports it without a prefix, as I recall. Current Chrome may support it with a -webkit prefix, maybe.

Leave a Comment

Line and paragraph breaks automatic, e-mail address required but never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Remember to encode character entities if you're posting markup examples! Management reserves the right to edit or remove any comment—especially those that are abusive, irrelevant to the topic at hand, or made by anonymous posters—although honestly, most edits are a matter of fixing mangled markup. Thus the note about encoding your entities. If you're satisfied with what you've written, then go ahead...


April 2012
SMTWTFS
March May
1234567
891011121314
15161718192021
22232425262728
2930  

Sidestep

Feeds

Extras