There is a sentiment that leaving math calculations in your CSS is a good idea that I agree with. This is for math that you could calculate at authoring time, but specifically chose not to. For instance, if you needed a 7-column float-based grid (don’t ask), it’s cleaner and more intuitive:
.col {
/* groan */
width: 14.2857142857%;
/* oh, I get it */
width: calc(100% / 7);
}
You could probably prove that the calc()
takes the computer 0.0000001% longer, so explicitly defining the width is technically faster for performance reason — but that is about the equivalent of not using punctuation in sentences because it saves HTML weight.
That math can a little more complicated as you continue. For example, like in our use cases for calc() article, what about columns in that 7-column grid that span?
.column-1-7 {
width: calc(100% / 7);
}
.column-2-7 {
width: calc(100% / 7 * 2);
}
.column-3-7 {
width: calc(100% / 7 * 3);
}
I’d say that’s rather clean to read and manage.
The readability of the math can be enhanced by comments if it gets too complicated. Say you are trying to account for a margin-based gutter with padding inside of an element:
.parent {
width: 600px;
padding: 18px;
}
.left {
/* base width - 1/2 horizontal padding */
width: calc(400px - 18px);
margin-right: 1rem; /* gutter */
}
.right {
/* base width - 1/2 horizontal padding - gutter */
width: calc(200px - 1rem - 18px);
}
Again, I’d say that’s pretty readable, but it’s also a good amount of repetition. This might call for using variables. We’ll do it with CSS custom properties for fun. You have to pick what is worthy of a variable and what isn’t. You might need fewer comments as the code becomes somewhat self-documenting:
.parent {
--padding: 18px;
--gutter: 1rem;
width: 600px;
padding: var(--padding);
}
.left {
width: calc(400px - var(--padding));
margin-right: var(--gutter);
}
.right {
width: calc(200px - var(--gutter) - var(--padding));
}
That is a decent balance to me. Here’s a step further:
.parent {
--padding: 18px;
--gutter: 1rem;
--parentWidth: 600px;
--leftSize: 2/3;
--rightSize: 1/3;
width: var(--parentWidth);
padding: var(--padding);
}
.left {
width: calc(calc(var(--parentWidth) * var(--leftSize)) - var(--padding));
margin-right: var(--gutter);
}
.right {
width: calc(calc(var(--parentWidth) * var(--rightSize)) - var(--gutter) - var(--padding));
}
Every single number has been given a variable in there. Too far? Maybe. It certainly makes those width declarations pretty hard to wrap your head around quickly. Ana Tudor does some serious stuff with calc()
, as proof that everyone’s comfort level with this stuff is different.
One of the things that made me think of all this is a recent article from James Nash — “Hardcore CSS calc()” — where he builds this:
While the solution took a heavily math-y road to get there, it ends up being only sort of medium-level calculation on the ol’ complexity meter. And note that not everything gets a variable’ only the most re-used bits:
Source: CSS-tricks.com