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.
- The WordPress CSS Coding Standards says you shouldn’t use them. Do any others?
- If you’re using icon fonts, remember they are fonts, so they change size. You can’t “reserve space” for them somewhere in pixel values, as the font size can change but the pixel value won’t.
- I’d like to keep this blog post updated with good examples of magic number fails, so if you have any classics, comment below.
- What if you are trying to center an image and text. vertical-align does pretty good, but I find it’s often 1px off or so so I
postion: relative; top: 1px;
it. Is that a magic number? Not sure.
Biznarf.
Great post Chris!
Little typo in the last SCSS demo. It should be
$topDistance: 37px
instead of$topDistance = 37px
. :)right. thx.
I assume these are magic numbers as well, I’ve always referred to them as such, when you get a Photoshop comp and columns like the main column and sidebar widths are just a few pixels off. Like the sidebar might be something like 273px wide and your main column width is 667px.
When I get comps like this I sometimes to round those to 275px and 670px as those seem less “magical” and more coherent to a grid.
I find really good designers use Photoshop guides and work off a grid. This makes coding out the layout really easy, no magic numbers.
I think it’s more of a web developer point of view :) In design if numbers are related and an overall proportions is there, any number is good. 975 can make more sense than 970 in a design and it would be a compromise to use 970 just because is an even number.
Having a sidebar that’s 273px isn’t a “magic number”, it’s just layout.
Having an absolutely positioned sibling element with is “left: 273px” so that it lines up with the right side of that that same sidebar is now a “magic number”. As soon as the sidebar changes size, either directly or through padding/margin/border (depending on your box model), the layout of the absolutely positioned item no longer works.
I agree. A grid abstracts numbers in favor of divisions. Essentially, a pixel doesn’t have meaning today anyhow, but a designer isn’t thinking about literal pixels in the sidebar anyhow. He’s thinking of a the sidebar as a proportion of the content (about half its width, 1/3 its width etc.)
One of the best things, in my opinion, about fluid layout is that the numbers are usually less guilty of being “magic” numbers.
Those kind of numbers are common fractions and easy to quickly understand. Once we see the vw unit (viewport width) used more, things will become even more clear.
I’m guilty of z-index magic numbers. Technically, it would make sense to name my layers and use those names (using sass or less) but I just try to keep it to only a couple of layers instead.
My fave (and one I’m guilty of using) is:
I do the exact same thing sometimes, but I think it’s less magic number and more me being lazy about figuring out z-index priorities. It’s an element that is always supposed to be on top of everything regardless of what else comes in so, as long as no one uses the same “hack”/”lazy coding” pattern with a larger number, no problems.
I personally use flexible widths for things. That being said, I still have quite a few magic numbers. For example;
Could be considered a magic number. Once something so good, now something so bad. I personally slowly convert all my projects into using % for widths and if you’re a future-friendly developer like me, you appreciate the hell out of
-webkit-calc
.I, too, was guilty of this previously. I don’t think this can be considered a magic number, however. If a user increases text size, everything within the wrap should still work fine. If it does cause a problem, then it would be more an issue with the inside elements than the wrapper.
I build everything with
%
as much as possible now, too, though. Fluid layouts certainly are more accommodating and fit in with responsive design much better. Replacingpx
with%
orems
seems to be a pretty general fix for using magic numbers.Good points, all. Figuring out how to keep from using magic numbers in CSS is definitely a chore.
BTW:
#pedant-hat { status: on }
Magic numbers not actually “unnamed numerical constants”, that’s a misnomer. They are “unnamed numerical literals.” Just saying… :)
#pedant-hat { status: off }
Hey Chris, i’m just wondering in what case do you use “-webkit-transform: translateZ(0);”, thanks!
First result on Google
Take a look at the Hardware Acceleration section.
Thanks for the information Will.
A very excellent Post, Chris. Magic numbers in programming, as I’m sure you know, are often solved by constants. This is another reason why it’s a really good idea to get familiar with ems. Even if you write all your font-sizes in pixels, ems are an essential tool in a web designer’s tool belt.
I often find that those that rely on pixels came from a print background where the medium is absolute. Understanding GOOD coding standards helps a designer not to rely on magic numbers. You gotta know your canvas if you’re going to paint on it!
My favorite magic numbers are colors and though many designers want to choose the exact color, they should ALWAYS be naming them in Sass or Less. #F3D210 is NOT a good naming choice!
This is much better:
I know there are those that say you should use $brand-color or something, but I’m all for named colors.
Usually I find that a GOOD developer/designer that applies DRY (Don’t repeat Yourself) principles falls more easily into the pit of success!
Although I do the same thing ($red, $light-red), I always feel guilty when doing it. What if at some point it’s decided that all the red items should be made green, because the red is scaring away visitors from clicking? You’d get:
Every now and again I feel so guilty, I change the variable names to something like $accent, $accent-light etc…
Off topic, but I like to mix the two styles, grouping sass/less color variables thusly:
I can change my button border color without redefining slime green.
The best solution to magic numbers that can’t be avoided is to comment them up. Explain why the number came to be, what will break if it changes etc, so when you come back to it you know it’s purpose, are aware of the implications and will tread carefully
For the different height box problem, you can get away with using
display: inline-block
andvertical-align: top
. Admittedly, you then encounter the next issue of spaces between items which are inline-block, but it’s a trade off I guess! See this pen for an example: http://codepen.io/WickyNilliams/pen/EFvdsIf the staggered look is OK, you can use inline-block with multiple columns as well. Here’s a fork of yours: http://codepen.io/chriscoyier/pen/eFsrb
That’s pretty cool, hadn’t thought of using columns at all! You’ve just met my “learn something new” quota for today :)
Strangely the container doesn’t completely collapse to the height of the columns though?
Very interesting, and I also learned something new:
text-overflow: ellipsis
Thanks Chris! ;)
Letter spacing in ems is fragile as heck as it misunderstands the notion that most if not all webkit browsers only handle letter spacing in units rounded to the nearest pixel, while others do allow fractional letter spacing.
Each time I see people do that I tend to interpret it as a mistake by someone who is new to web development.
I have used EM-based letter spacing for years and I have yet to run into any issues. I have been in this field for 10 years. Who cares if it’s getting rounded to the nearest pixel in some browsers… at least the letter spacing will grow and shrink with the text size.
One of the BIGGEST uses for magic numbers is when a developer/designer tries to equate an EM to some other value. “And em.. oh that’s just 16px!?!” This possibly the worst of all occurrences of mystic numerals because it would appear to be a good coding practice, on cursory inspection at least, since dimensions and lengths are given in EMs which everybody loves. Normally it would be a good thing, but not when do it as a match for a background image size, or things like that.
I like Chris’ example about closing gaps in inline elements. I use what I call a semi-magic number, that is I know it’s calculated on specific situation .. but there really is no better solution. for example, I have found that -.3em margin will close up those gaps, regardless of font size .. AS LONG AS IT A SERIFED font family… but since my stack is composed of serif fonts, and defaults to serif.. then I know I the layout will hold 96% of the time… but I also know i will need to recalculate if I use a san-serif font. In fact, that’s my CSS tick.. :) I sometimes set the root for to mono space because it makes this kind of manipulation easier.
I guess what I boil down ‘magic numbers’ to is when developers use a constant as a hack for comparing apples to oranges.
Very interesting. But as Kevin Attfield, i think that sometimes width:273px isn’t a magical number, it’s just a layout. But i’m pretty interested by -webkit-calc, it’s such a shame that only Safari 6+ and Chrome 19+ use them correctly. I recently had a problem on a liquid layout and i really wished some calc had been possible : it could have resolved all my problems.
I’m actually very surprised at all of these px examples.
We have always built sites using percentages and ems, which makes for far more fluidity (and better Accessibility).
The only time that I use pixels is when I am measuring a pixel width, e.g. if I have a pixel-based background icon, then I will measure the element’s left-hand padding in px.
DR
The way I see it, magic numbers are a good thing. What lacks however, is the documentation that goes along with them.
Since we tend to derive magic numbers by trial and error, it makes sense to not document each attempt made. But that can be bad, as it can lead to no documentation at all.
Solution: keep your magic numbers out of your main code and in a seperate stylesheet.
CSSWizardry just posted an article relevant to this (http://csswizardry.com/2013/04/shame-css/). Magic numbers seem like a great candidate for shame.css material. Great article though, as always Chris.
Just like some of the previous commenters said, most magic number problems can be avoided by using ems percentages ( or automatic browser values ). These should – in my opinion – be used just about everywhere…including max-width media queries.
Thanks for the post. I already passed 3 years as a web designer. I know a lot of the things about css but this post about magic numbers is unknown to me. learned a new thing. Many many thanks for sharing. Hope, will learn a lot from here in future. Checking the box ” Notify me of new posts by email” to get new posts from here.
Regards
Paul
I think “magic numbers” are another case in CSS where you can get a way with them on a small site, but they become a problem when you try and scale. One of the differences between building a small marketing web site and a large application.
Obviously, no blanket answer here. You do what you have to do to get the job done and there are cases for everything. Just like there are cases where OOCSS is good and cases where it’s bad.
I would add that while ems and percentages are safe bets, beware when the two start overlapping, especially in responsive designs. They are flexible values, but they have no relationship to each other, making it hard to calculate squares, circles, and vertical/horizontal alignments of such.
Not entirely on topic, but any reason for this as opposed to numerical values for vertical-align if a value of middle isn’t exactly what you want?
Ah right! I often forget
vertical-align
takes lengths.Great article, I’ve fallen victim to a lot of these scenario’s but have been focusing on not getting caught in the trap.