Why Your calc() Function in CSS Might Be Broken
Tags: css, webdev, productivity, beginners
Published: 2021-04-01 16:50:23

*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:
```css
.main {
  width: calc(10px+100px); /* ❌ no whitespace surrounding `+` */
}
```

However, adding whitespace around the `+` operand fixes the issue:
```css
.main {
  width: calc(10px + 100px); /* ✅ `+` surrounded by whitespace */
}
```

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](https://developer.mozilla.org/en-US/docs/Web/CSS/calc#notes):

> `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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8neh60ycwk58mlxkubs.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tf1ctsy5hmj93zf98cl4.gif)

## 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`](https://stylelint.io/user-guide/rules/list/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.

## Become a skilled Node.js developer

Every other Tuesday I send an email with tips on building solid Node.js applications. If you want to grow as a web developer and move your career forward with me, [drop your email here 💌](https://maximorlov.ck.page/0076aaf499).