DEV Community

loading...
Cover image for Why Your calc() Function in CSS Might Be Broken

Why Your calc() Function in CSS Might Be Broken

maximization profile image Maxim Orlov Originally published at maximorlov.com ・3 min read

This article was originally published a day earlier at https://maximorlov.com/why-your-calc-function-in-css-might-be-broken/

A CSS bug is a nightmare for every developer. Not only is CSS hard to debug, but it can also go wrong in so many ways.

You've fiddled with the calc() function about a dozen times now but no matter what you try, you can't seem to figure out how to make it work.

Only if writing CSS came to you as naturally as writing JavaScript. You would immediately spot the bug and move on to other tasks.

In this article, you'll learn the common mistake developers make when writing mathematical expressions in CSS.

You'll also learn how to debug calc() and see the computed value change in real-time. You'll finally fix the issue and make sure you'll never have to face it again.

Whitespace and mathematical expressions in CSS

There's a subtle, but important, rule in CSS when it comes to writing mathematical expressions:

The + and - operands must be surrounded by whitespace.

This calc() expression won't work:

.main {
  width: calc(10px+100px); /* ❌ no whitespace surrounding `+` */
}
Enter fullscreen mode Exit fullscreen mode

However, adding whitespace around the + operand fixes the issue:

.main {
  width: calc(10px + 100px); /* ✅ `+` surrounded by whitespace */
}
Enter fullscreen mode Exit fullscreen mode

As a backend developer, I really tripped over this one. In Node.js, whitespace around operands is irrelevant.

MDN has to say the following about how the calc() expression is parsed:

calc(50% -8px) will be parsed as a percentage followed by a negative length — an invalid expression — while calc(50% - 8px) is a percentage followed by a subtraction operator and a length. Likewise, calc(8px + -50%) is treated as a length followed by an addition operator and a negative percentage.

Using our example, the expression calc(10px+100px) is parsed as a length (10px) followed by another (positive) length (+100px).

The plus sign (+) is mistaken for a positive integer sign instead of an addition operator which renders the entire expression invalid.

Adding whitespace around the plus sign: calc(10px + 100px), fixes the issue. The plus sign is now correctly parsed as an addition operator.

The / and * operands don't require whitespace, but adding it is recommend for consistency and to avoid confusion.

How to debug calc()?

Debugging calc() is a bit tricky.

Debugging anything in CSS is difficult. Besides border: 1px solid red, what else is there to know, right? 😅

With calc(), the computed value can be different depending on which element it is used. While some expressions such as calc(10px + 10px) always evaluate to the same result, other expressions such as calc(10px + 50%) are dynamic and will change depending on context.

The browser evaluates the expression when it's used with an element. In other words, the final value only exists until it's been used within a property.

An, albeit hacky, way to debug calc() is using Developer Tools in your browser. With DevTools open, select the element you want to apply calc() on, and add a CSS property width to it with the calc() expression. If the expression is invalid it will be negated/struck through.

With DevTools open, 1. Select any element and 2. Add a width property with the calc expression you wish to debug. If the value is struck through, it means the expression is invalid

If it's valid, you'll see the result calculated as the width property of the element. In Chrome, the value is visible in the "Computed" tab. If the expression depends on the width of the browser, resize the window to see the value change in real-time.

Chrome DevTools open with device toolbar selected. When the window is resized the computed width value changes as well because the calc() expression depends on it

Avoiding the issue in the future

If you're linting CSS, you can use a rule that warns you when an operand isn't surrounded by whitespace. In Stylelint, this rule is named function-calc-no-unspaced-operator. This is an ideal solution in a working environment where you want to formalise the process among your colleagues.

Unfortunately, linting CSS doesn't cover the scenario when you're using calc() in the sizes attribute of the img tag.

My advice is to always surround mathematical operands in CSS with whitespace. If you make this a strict rule for yourself, you won't face this issue again when writing calc() expressions in CSS.

Discussion (2)

pic
Editor guide
Collapse
afif profile image
Temani Afif

There is also the trap of the 0 in calc (related: stackoverflow.com/a/55406181/8620333) that is also a trap for min/max/clamp (stackoverflow.com/a/62523544/8620333)

Collapse
maximization profile image
Maxim Orlov Author

Today I learned! Thanks for sharing :)