Despite the super fun sounding name, magic numbers are a bad thing. It is an old school programming term for “unnamed numerical constant”. As in, just some number plunked into the code that is probably vital to things working correctly but are very difficult for anyone not intimately familiar with the code to understand what it is for. CSS is loaded with unnamed numerical constants, but they are usually paired with properties and in the context of a selector so there is little mystery. There are magic numbers in CSS though, and they are still bad.

Magic numbers in CSS refer to values which “work” under some circumstances but are frail and prone to break when those circumstances change. They are usually always related to fonts in some way or another. They are created by an author who likely only tested in their own browser under ideal conditions. Let’s take a look at some examples so we all know what they are and hopefully can avoid them in the future.

Look at this simple set of tabs:

Each of the tabs is set to width: 100px; . In this example 100px is our “magic number.” There are any number of things that can go wrong with this. Simply adding another tab with longer text demonstrates that:

A bit awkward and likely undesirable. We could prevent the wrapping with white-space: nowrap; but that’s possibly worse:

Our tabs would be less prone to breakage if we use min-width instead:

Or perhaps no width at all:

If you were dead-set on having all the tabs the same size, you could do overflow: hidden; and text-overflow: ellipsis; perhaps:

In that case, you’d probably want a title attribute so there is some way to reveal the entire tab name. You might think this could be solved from the Content Management System side by only allowing tab names to be a certain number of characters long. But what about users who increase font-size from their end for accessibility reasons? This fixed sizing might be hurting them.

In a recent post Line-On-Sides Headers, I used a line-height value that was a magic number. Let’s say you used the technique around text with a fancy @font-face font. Let’s say that font doesn’t load or the user overrides it or the page is being viewed in a browser that don’t support @font-face. The fallback font will load, and that fallback font might have drastically different sizing than the custom font. The lines on the outside of the fallback font are now awkwardly placed, not centered like we wanted. Magic number fail.

This particular example is a bit contrived, but I’m sure you’ve all seen custom fonts that have super crazy x-heights and stuff.

Let’s say you have a bunch of boxes with different amounts of content in them. You want to arrange them into a grid, so you float them left. Kind of a mess:

Well hey if they were all the same height this wouldn’t be a problem!

That is, if the user viewing the site has the exact same font-size setting as you. But users can change that.

And now a big sad trombone:

min-height instead would prevent the overlapping weirdness, but then the boxes are of different size and the float problem happens again. I’m not going to go too far into solutions because this is so abstract already, but perhaps you could use scrolling on the boxes, or use some JavaScript to adjust sizes, or user some other kind of layout.

Harry Roberts points out a classic example of a magic number in his article Code smells in CSS.

.site-nav > li:hover .dropdown{ position: absolute; top: 37px; left: 0; }

This would be for a CSS powered dropdown menu. The menu is hidden off-screen until the parent list item is hovered, then the dropdown moves into view. It should be placed at the bottom of the parent menu item. For the developer that wrote this code, in their current browser, that menu item was 37px tall. I’m sure you can imagine that isn’t always true. 37px is a magic number. Harry suggests top: 100% instead meaning “all the way from the top,” which is far less prone to breakage.

In the article Fighting the Space Between Inline-Block Elements, -4px is a number quoted for margin that can close those gaps. That is definitely a magic number. 4px just happens to the width of a space in a good number of fonts at the default 16px font-size .

Change that font-family to something like Monaco? Broken. Change the font-size to anything larger or smaller? Broken.

See that article for other fixes.

Definition Confusion

Because we’re trying to say “don’t use these,” it is important we we define the term properly as it relates to CSS. I’ve seen a number of threads in the past where not everyone is on the same page. (1) (2) (3).

Here’s some examples:

-webkit-transform: translateZ(0);

Magic number? Nah. Just a little hack we used to use for performance.

.parent { padding: 22px; } .child { bottom: 22px; left: 22px; }

Magic number? Nah. It’s a weird number but it’s not magic. The child element is being positioned to the bottom left corner of an element, sans-padding. Because those numbers match up, it makes sense what is going on. If the were all different, that would mean there is likely little tweaky bits going on related to font-size and it would be a magic number.

top: 37px;

Let’s say this is a magic number, like from the dropdown menu example above. Can was solve it with Sass?

$topDistance: 37px; .dropdown { top: $topDistance; }

It’s no longer an “unnamed” numerical constant right, because we named it? It’s still a magic number in CSS. It’s just as fragile as it was before.

letter-spacing: -.05em;

Magic number? Nah. If it was in pixels it probably would be, because the pixel value remains constant so the effect of it changes depending on the current font-size. Huge font-size, barely any change, small font-size, big change. The fact that this is in a relative unit makes it less fragile.

AND IN CONCLUSION

Man I hate this section of blog posts but it’s nice to have a little dumping ground for little things that didn’t work themselves in elsewhere.