The wonderful calc() function

Sitting right at the top of my CSS wishlist was always the implementation of the calc() function. With it now being supported by not only Firefox 4 but Internet Explorer 9, I think it’s time for a quick overview on how useful calc() can be and why it would be great to see more usage of it.

What is calc()?

The calc() function can be used to specify lengths. For example, you can use it for values of borders, margins, paddings, fonts, etc. Calculating widths can be extremely complicated, especially in fluid layouts; calc() is unique because it lets you make these calculations within the CSS itself.

It accepts addition (“+”), subtraction (“-“), multiplication (“*”) and division (“/“).

Let’s look at a simple example:

div {
	width: calc(100% - 20px); }

Easy, right? You can also have more than one calculation within a single function, for example:

div {
	width: calc(100% - 20px + 2px*2); }

In the current specification, it is stated that multiplication and division expressions have precedence over addition and subtraction. This means that, in the previous example, “2px*2” will be calculated before the other two expressions. Also, note that divisions by zero will (or should) result in an error.

The spec is not yet finalised (there is an Editor’s Draft version that expands on the CSS3 Values and Units Working Draft version), but these are the basics.

A simple use case

To show calc’s usefulness further, I’ve created a basic layout where I’ve applied it generously.

The layout consists of a main content container on the left, a sidebar on the right, and a footer, below the previous two. Here is the basic markup with only part of the text being shown, for brevity:

<div class="wrapper">

	<div id="main">
		<h1>Far far away…</h1>
		<p>Far far away, behind the word mountains…</p>
	</div>

	<div id="accessory">
		<ul>
			<li><a href="#">Far far away…</a></li>
			<li><a href="#">Separated they live…</a></li>
			<li><a href="#">A small river named…</a></li>
		</ul>
	</div>

	<div id="footer">
		Visit the article…
	</div>

</div>

After the (hopefully) self-explanatory simple reset (please check the full CSS in the example document), font properties and defining the links, I will define the look of my body element:

body {
	background: #E8EADD;
	color: #3C323A;
	padding: 20px; }

After that, I will say that the main container div should be full width (100%) minus 40px and aligned horizontally in the middle of the viewport:

.wrapper {
	width: 1024px; /* Fallback for browsers that don't support the calc() function */
	width: -moz-calc(100% - 40px);
	width: calc(100% - 40px);
	margin: auto; }

In the CSS above, I have also added a fallback width for browsers that don’t support the calc() function, and the vendor prefix for Firefox 4.

Following this, I will set the borders, width and margins of the main container div, and I will float it left:

#main {
	border: 8px solid #B8C172;
	float: left;
	margin-bottom: 20px;
	margin-right: 20px;
	padding: 20px;
	width: 704px; /* Fallback for browsers that don't support the calc() function */
	width: -moz-calc(75% - 20px*2 - 8px*2);
	width: calc(75% - 20px*2 - 8px*2); }

So what is happening in this calc() function? I am stating that I want my container div to be 75% wide (75% of its parent container, remember), but from these 75% I need to subtract “20px*2” to account for the padding on each side, and “8px*2” to account for the border on each side.

Moving onto the sidebar, I want it to occupy the remaining 25% inside the parent container, but this value will have to allow for padding, borders and the margin of the sidebar div (20px).

#accessory {
	border: 8px solid #B8C172;
	float: right;
	padding: 10px;
	width: 208px; /* Fallback for browsers that don't support the calc() function */
	width: -moz-calc(25% - 10px*2 - 8px*2 - 20px);
	width: calc(25% - 10px*2 - 8px*2 - 20px); }

Deconstructing “calc(25% - 10px*2 - 8px*2 - 20px)”, we have the original 25%, minus “10px*2” to account for the padding on each side, minus “8px*2” to account for the border on each side, minus “20px” to account for the main container’s right margin.

The footer is simply a full width div, I shan’t bore everyone by explaining that.

Because the sidebar becomes too small after a certain point, I’ve also included a simple media query that unfloats the main and sidebar containers, and recalculates their widths so they are 100% wide minus their respective padding and border values.

@media screen and (max-width: 768px) {
	#main, #accessory {
		float: none; }
	#main {
		margin-right: 0;
		width: -moz-calc(100% - 20px*2 - 8px*2);
		width: calc(100% - 20px*2 - 8px*2); }
	#accessory {
		width: -moz-calc(100% - 10px*2 - 8px*2);
		width: calc(100% - 10px*2 - 8px*2); }
}

This is a very simplistic use case, but hopefully it’s enough to spike your interest and prompt you to find out more about wonderful calc().

Browser support

Calc is supported by IE 9 and Firefox 4 (which requires the -moz-calc vendor property). I can understand, however, how this can be a bigger problem if compared to the relatively deficient browser support of things such as animations. While animations are accessory, incorrect measurements can break a site.

This does not mean though that we shouldn’t be trying these out. If Firefox and IE have made the effort to implement this, and these are the browsers with the biggest market share, I would suppose the others will follow suit (I’m not sure whether WebKit or Opera are working on this or not, but do let me know if they are).

In my example, I’ve opted for including fallback, absolute lengths for non-comforming browsers, which gives them a non-fluid layout. This might not be acceptable in your particular case though, but it is for my use case.

Reference

If you’d like to know more about calc(), head on to the following resources:

Final note

Along with few other CSS3 properties, calc() is one of those new pieces of CSS that can truly make our lives easier. I haven’t tested it in terms of performance, so I don’t know how big an impact all these calculations might have on the browser, but I’d guess it won’t be more consequential than all those transitions and transforms that everyone seems to be so happy to indiscriminately add to their sites.

So, have you used calc() on a project? Is this something you feel is a welcome addition to CSS? I’d love to hear your thoughts.