Keeping Track Of CSS Sizes With Calc()
I’m back with another calc() trick I stumbled upon.
This sprung out of my desire to design with odd numbers. Odd numbers of things in design pretty much always come out more visually interesting than even numbers. With even numbers, everything can pair up neatly: for every one thing, there is another that goes with it. But with an odd number, one of those things is going to stand out. In design, that’s useful.
Hard Numbers To Deal With
The trouble is, math-wise, odd numbers are often harder to use. I do a lot of designing and prototyping in the browser, and I often want to quickly create new rows or columns, and need to know how wide to make them. If I’m working with a six-column grid, it would not be a huge stretch to memorize each column width. We come up with the following percentages:
|Columns spanned||Width (rounded off)|
|1 of 6||16.666%|
|2 of 6||33.333%|
|3 of 6||50%|
|4 of 6||66.666%|
|5 of 6||83.333%|
|6 of 6||100%|
Relatively speaking, these are fairly easy numbers to remember. But what if we go one column higher? Suddenly they appear almost random.
|Columns spanned||Width (rounded off)|
|1 of 7||14.286%|
|2 of 7||28.571%|
|3 of 7||42.857%|
|4 of 7||57.143%|
|5 of 7||71.428%|
|6 of 7||85.714%|
|7 of 7||100%|
While I could take the time to commit these conversions to memory, what if my next project has a nine-column grid? Or how about a more expansive 16-column layout? The point is, with all this potential for complexity, we can’t hope to be able to call all of the numbers we need immediately off the top of our heads. How can we make this easy?
calc() To The Rescue
calc() allows us to do mathematical operations in CSS, which means we can take what we already know—the number of total columns and the desired number of spanned columns—to figure out what we don’t know—how that translates into a specific percent. Say we want to span five out of seven columns. To figure out the percentage, we usually divide seven by five, multiply by 100, and slap a percent sign on it. Let’s start by putting those numbers in the calc() function:
width: calc((5 / 7) * 100);
That gives us 71.428571428571. Already, I’m glad I don’t have to memorize this number. This result is close, but if we were to run with it, the browser wouldn’t have any idea of what we’re talking about. That’s because there’s no unit. To the browser, this is just a number that doesn’t mean anything. 71.4 of what, exactly? We still need to add that percent sign. My first instinct was to just tack it on:
width: calc(((5 / 7) * 100)%);
Unfortunately, that won’t work. The browser just doesn’t get what you’re trying to do. You have to speak the browser’s language, and you do that by speaking in math! To add on a unit, we simply need to multiply the entire formula by 1 of our units (in this case, one percent).
calc(((5 / 7) * 100) * 1%)
This works because the formula is taking advantage of the distributive property. In other words, it’s mathematically sound, so the browser can parse it!
Cunning mathematicians will already recognize that it’s possible to simplify this formula even further. If you know how to make these optimizations, by all means, do it. But my point is, generally speaking, if you’re in need of adding a unit on the fly, multiplying by 1 of the desired unit is a nice trick. In the case of columns, you can keep the logical context in the code, and you’ll always know how many columns you were going for when you come back to it later:
width: calc((1 / 7) * 100%);
width: calc((2 / 7) * 100%);
width: calc((3 / 7) * 100%);
width: calc((4 / 7) * 100%);
width: calc((5 / 7) * 100%);
width: calc((6 / 7) * 100%);
width: calc((7 / 7) * 100%);
On top of that, you’ll never have to look at a long, crazy percentile number again.
In the case of setting a relative font-size, you can use the same idea. If I want my font-size to be 20px, and I know that my root em is 16px, I can calculate the font-size on the fly:
font-size: calc((20 / 16) * 1rem);
Say I want to set a margin relative to the size of my font. If my font-size is 17px, and I want my margin to be 15px, I can do it like this:
margin: calc((15 / 17) * 1em);
Nice and consistent. Now you can take advantage of basic mathematical properties with calc() to simplify your code. If you’re interested in more mathematical magic, I’ve also written about creating minimum margins with calc(). Now, go forth, and multiply by one.