Fixed Monospace Sizing
Published 14 years, 6 months pastMonospace text sizing is, from time to time, completely unintuitive and can be quite maddening if you don’t look at it in exactly the right way. Fortunately, there is a pretty simple workaround, and it’s one you might want to consider using even if you weren’t aware that a problem existed.
But first, allow me to lay some foundations. Assuming no other author styles beyond the ones shown, consider the following:
span {font-family: monospace;} <p>This is a 'p' with a <span>'span'</span> inside.</p>All right, what should be the computed
font-size
of the span
element? Remember, there are no other author styles being applied.
The savvier among you will have said: “It depends, but most likely 13px
.” That’s because here, the size of the monospace text is controlled by the browser’s preferences. The vast majority of users, of course, have never touched their default settings of “16” for proportional fonts and “13” for monospace/fixed fonts. For them, then, the answer is 13px
. Similarly, if I’d asked about the p
element’s computed font-size
, the answer would be: “It depends, but most likely 16px
.”
So let’s add a bit more and see where we land.
span {font-family: monospace; font-size: 1em;} <p>This is a 'p' with a <span>'span'</span> inside.</p>
As before: bearing in mind that there are no other author styles, what should be the computed font-size
of the span
element?
In this case, building on the previous question and answer, you might say, “It depends, but most likely 16px
.” The reasoning here is pretty straightforward: since the computed font-size
of the p
element is 16px
, the font-size: 1em;
assigned to the span
will result in it having the same size.
And that’s true… in two of five browsers I tested: Opera 10 and Internet Explorer 8. In the other three I tested—Firefox 3.6, Safari 4, and Chrome 4—the computed (and rendered) font-size
of the span
is 13px
, the same as in our first example. This result holds true if the rule is changed to use font: 1em monospace;
instead of the two separate properties. The behavior continues to persist even when adding specific font families, like Courier New, Courier, Andale Mono, and so on to the rule. It also persists if 1em
is converted to 100%
.
So in other words, even though I have written CSS that explicitly says “Make the font-size
of this element the same as its parent”, three of five browsers apparently ignore me.
I say “apparently” because what’s happening is that those browsers are allowing the span
to inherit the default font-size
from its parent (and thus, indirectly, all its ancestors), but the default font-size
is medium
. If you go look up medium
, you find out that it doesn’t have a defined numeric size. So what those browsers do is equate medium
with the preference settings, which means it’s different for monospace fonts than for everything else.
In other words, those three browsers are doing something like this:
- This
span
needs to have the samefont-size
as its parent element. - The parent’s
font-size
ismedium
, even though when my web inspector (or an author’s DOM script) asks, I report the16px
I used to output the text. So thespan
‘sfont-size
is actuallymedium
. - This
medium
-sizedspan
is using a monospace font. The preference setting for monospace is “13”, and I equatemedium
with the preference setting, so I’ll output thespan
using 13-pixel text.
Opera 10, as I said, doesn’t do this, even if your monospace font preference setting is the default value of “13” or indeed different from the preference for non-monospace fonts. And IE8 doesn’t appear to do it either, although you can’t set numeric font size preferences in IE8 so what it’s actually doing is open to interpretation. Oh, IE8, you inscrutable little scamp, you.
All that might seem reasonable enough, but it turns out that’s not the whole story. No, the three resizing browsers are being a good deal more “clever”, if that’s actually the word I want, than that. In fact, what those browsers do makes it seem like they use the two preference settings to create a ratio, and that ratio is used to scale monospace text. That’s not actually what’s happening, but it looks that way at first. To see what I mean, let’s consider:
span {font-family: monospace; font-size: 2em;} <p>This is a 'p' with a <span>'span'</span> inside.</p>
Again: in the absence of other author styles, what should be the computed font-size
of the span
element?
The answer: “It depends, but most likely 26px
as long as we aren’t talking about Opera 10 or IE8. If it is one of those two, then most likely 32px
.” Why? Because the resizing browsers see the font-size: 2em;
declaration as “twice medium
” and twice 13 is 26. Opera 10 and IE8, as previously established, don’t do the resizing. Or else they simply interpret medium
as being equal to the proportional font size preference setting. Whatever.
Okay. So what all this means is that in many browsers, you can declare that an element’s font size should be twice the size of its parent’s and have it actually be 1.625 times the size — or, if you want to look at it another way, 0.8125 times the size you expected it to be. The 0.8125 comes from 26/32, which of course reduces to 13/16. If you were to adjust your browser’s preferences so the monospace setting is “15”, then monospace fonts would be 0.9375 (15/16) times the expected size.
But — and here’s where things get really fun — this is not always so. See, you may not have run into this problem if you’ve been declaring specific font families with no generic fallback. Consider this variation (note that I dropped back to 1em
for the font-size
):
span {font-family: "Courier New"; font-size: 1em;} <p>This is a 'p' with a <span>'span'</span> inside.</p>
This time, in every one of the five browsers I mentioned before, assuming the browser defaults, the computed (and rendered) font-size
of the span
will be 16px
. Not 13px
. And the only difference is that we switched from a generic font family to a specific one.
“Hey presto!” you shout. “We’ll just tack the generic family on the end there and be right as rain!” Sadly, no. For if you do this:
span {font-family: "Courier New", monospace; font-size: 1em;} <p>This is a 'p' with a <span>'span'</span> inside.</p>
…then the answer to the question I keep asking will be: “It depends, but given browser defaults it will be 16px
, unless we’re talking about Safari. In that case, it’s 13px
.”
Really. Alone among the browsers I tested, Safari goes back to doing the resizing when you provide a generic fallback to your specific family. Or even multiple families. Do your best to make sure the user at least gets a fixed-width font, and you get a size smaller than you’d intended. (You can get the back story on this in a late-2006 post on the Surfin’ Safari blog.)
So what do we do? Get creative. That’s what the ARIA folks did in their specification’s style sheet, where they declare two font stacks: the first with a generic fallback, and the second without it. That works, but it’s ugly. I didn’t like that at all. And then, halfway through writing up this post, a fix came to me like a shot in the dark. Check this out:
span {font-family: "Courier New", monospace, serif; font-size: 1em;} <p>This is a 'p' with a <span>'span'</span> inside.</p>
This time around, the answer is: “It depends, but given browser defaults, 16px
.”
Really! Even in Safari! And in all tested browsers, it falls back to a generic monospace font at the requested size even if the specific family (or families) we declare aren’t available! This can be verified by altering the specific font family to something that doesn’t actually exist:
span {font-family: "Corier Neu", monospace, serif; font-size: 1em;} <p>This is a 'p' with a <span>'span'</span> inside.</p>
Monospacey goodness at the intended, parent-matching size. It’s enough to make a body believe in monotheism.
Since I generally assume that anything I devise was already invented by someone else, I went Googling for prior art. And wouldn’t you know it, the Wikipedia folks had worked it out around the end of last year. This, of course, supports my contention that Wikipedia is the new Steve Allen. I also found some claims that ending the font stack with monospace, monospace
would have the same effect, but that wasn’t borne out in my testing. Perhaps it worked in older versions of browsers but no longer does.
I did leave out another way to make monospaced fonts behave as expected, which you may have already figured out from the preceding: declare the font-size
for any parent of a monospaced element to be a length value, along the lines of body {font-size: 12px;}
. That will pass the length value down the document tree to the monospaced element via inheritance, which will use it without resizing it in every browser I tested. Though you may have heard that page zooming makes pixel-sized text okay, I’m not really convinced. Not yet. There are too many people who don’t know how to zoom, and too many whose browsers aren’t advanced enough to zoom pages. Even in page-zooming browsers, there are problems with pixel text. So I’m still on the ems-and-percentages bandwagon.
In fact, there are a fair number of details and extra browser oddities that I left out of this, as it’s already way more than long enough, and besides you don’t really want to hear the gory details of manually stepping through 37 different preferences settings just to verify a theory. Plus you already heard about the font-size
rounding investigation that spawned off of this one, about halfway through. I think that’s more than enough for the time being.
I should also lay down a caveat: it’s possible that this behavior will be interpreted as a bug by the Safari team and “fixed”, if that’s the word I want, in a future release. I really hope not — and if they’re looking for ways to improve how they handle monospace font sizing, I have a few suggestions — but it is possible. Adjust your expectations accordingly.
And with that, I’m going to stop now. I hope this will be useful to you, either now or in the future.
Comments (23)
You, dear sir, fight the good fight for the rest of us :-)
span {font-family: "Courier New"; font-size: 1em;}
This is a 'p' with a 'span' inside.
This time, in every one of the five browsers I mentioned before, assuming the browser defaults, the computed (and rendered) font-size of the span will be 32px. Not 26px. And the only difference is that we switched from a generic font family to a specific one.
According to the 1em in the example, shouldn’t 16px (13px) appear in the text (or vice versa)? Great post anyway.
Quite right, Dero. Thank you! I’ve fixed the error. While I was at it, I reworked some misleading text that I didn’t quite catch before publication (the part about the apparent ratio).
This has been driving me nuts for years. Thanks for figuring this out and for sharing.
Browsers certainly are fascinating creatures.
Brilliant. Thank you.
I had resorted to employing a large font stack with “sans-serif” as the fall-back. Now all I need to do, it seems, is add “monospace” ahead of “sans-serif”. Nice.
In 13 or so years of writing HTMl i can’t say i’ve ever had this issue come up, but thanks for the digging and explanation. It makes for a nice clean case study in implementing specs and where browser differences with seeming simple properties comes from.
Eric,
Part of what I do for the dev team here at Clinical Trial Select is the R&D and within that rubric try and chase down solutions for common web development problems so that coders can, well code. This post, which_must have taken a while to write, is a gem.
Thank you.
etienne taylor
ceo
clinical trial select, inc.
Wow. That is a truly impressive piece of detective work, and I’m glad I did not have to do it.
Is is the same on all platforms ? (ie: Windows/Linux ? I suspect you’re using a Mac)
Thank you, now I know why my monospaced code doesn’t have te same size in IE and other browsers !
Eric, I sit here after reading this with my face long, my mouth hanging open, feeling like I’ve been jostled and shoved so many different ways since Tuesday… I can’t imagine all you went through to discover and document all of this, and that it didn’t make you want to become anything other than a web designer/developer.
Now, please, go play with your kids, kiss your wife. Get the hell off that computer!!!
A chromium developer wrote some great pieces about monospace sizing in webkit.. Some good explanations of this mess:
http://neugierig.org/software/chromium/notes/2009/04/monospace-fonts.html
http://neugierig.org/software/chromium/notes/2009/09/monospace-fonts-workaround.html
Pingback ::
links for 2010-02-16 - ReFactor.it
[…] Fixed Monospace Sizing Monospace text sizing is, from time to time, completely unintuitive and can be quite maddening if you don’t look at it in exactly the right way. Fortunately, there is a pretty simple workaround, and it’s one you might want to consider using even if you weren’t aware that a problem existed. (tags: css typography fonts 2010 safari) […]
Pingback ::
Links LXXVI • Peter Kröner, Webdesigner & Frontendentwickler
[…] Fixed Monospace Sizing – Was für ein Zirkus nur um eine Schriftgröße geradezubiegen. Aber hey, immerhin geht […]
Thanks, Eric – this is excellent info for the obsessives amongst us :) I recently discovered a much more basic (though still relatively annoying) inconsistency in IE7’s font-size handling, namely that the default user agent styles appear to be applied in absolute sizes (more here:
http://www.fiveminuteargument.com/blog/user-agent-font-sizes). It’s staggering that these kinds of issues are not more widely known and understood.
Pingback ::
mysocialbrain: 09-03-2010 : protagonist
[…] Fixed Monospace Sizing font amusement Name: Required […]
Pingback ::
Meanwhile in Gotham City ← pseudopost.org
[…] Shared Eric’s Archived Thoughts: Fixed Monospace Sizing. […]
Just for extra entertainment value, an issue I’m sure anybody trying the “table method” for highlighted-code-with-line-numbers has come across, italicised Courier New is taller than regular and bold, meaning the numbers never line up… Unfortunately, most people’s monospaced font is Courier New! The only workaround I’ve found is just to not use italics.
(While “semantically” more correct, using a numbered list for the lines gives people “unexplained” # symbols when copy-pasting.)
Great information. I know that I have had a problem with this at times on a couple of WordPress sites. Thanks for sharing!
Jeremy @ http://www.thecommerceshop.com
That’s great hack. Would you say it’s still the best way to fix the sizing in 2019 still?
This solved it for me:
pre { fontsize: 1rem; }
That’s great hack. Would you say it’s still the best way to fix the sizing in 2021 still?
That’s great hack. Would you say it’s still the best way to fix the sizing in 2023 still?