How to Detect Font-Smoothing Using JavaScript

Update: Jan. 11, 2012

In an earlier article, I mentioned that Boing-Boing had a few issues when they wanted to use @font-face embedding inside their website. In short, the problem was that some fonts look bad on computer monitors without font-smoothing enabled in the operating system. This brought on a lot of discussion as to whether there was a way to detect whether or not font-smoothing was being used using JavaScript. I initially thought there wasn’t a way, but after seeing a promising but incomplete method of detecting font-smoothing, I spent a few days devising a way to do it.

I was more disappointed because Googling “javascript cleartype” did not point to anything useful. However, searching for “javascript font-smoothing” pointed me to an article that told me about Internet Explorer’s screen.fontSmoothingEnabled property. This gives us what we need … but only in Internet Explorer. How on Earth can we detect font-smoothing in other browsers, and in non-Windows operating systems?

Canvas to the Rescue

I then thought about about the screenshots I made for the @font-face in Depth article. Can a browser render a black glyph and detect if there is some sort of non-black pixel colouring around the its edges of the glyphs? A human can tell the difference: if there are some non-black pixels around the edge of the glyph, it must be using font-smoothing.

But web browsers can do this too! Just have the browser draw a letter in black inside a canvas tag, and then have it sift through the canvas’ pixels to see if there are any that are not pure black or pure white (more accurately, have the browser check the alpha channel to see if there are any semi-transparent pixels, which have a value that is not 0 or 255). If there are no semi-transparent pixels, then the algorithm assumes that no font-smoothing is being used. I wrote an JavaScript routine that does this – it starts from co-ordinate (8,1) and scans left to right, to the bottom of the canvas (any point on near the top on the left-hand side of the canvas would have done as well).

The result is a JavaScript object, TypeHelpers, which implements this routine in one method, hasSmoothing():

Example #1: JavaScript Font Smoothing Detection

Enough of theory … let’s look at it in practice! To show how to detect font-smoothing with JavaScript, I created a page that, when the page is loaded, checks to see if it can tell if font-smoothing has been implemented and tells the user. Here is the code that does this check:

Example #2: CSS Font Smoothing Detection

As implied earlier, this library can help CSS use different fonts if the browser is using a font-smoothing technology. For example, using the following CSS will allow a browser to use the Droid Sans embedded font only if it using font-smoothing — otherwise, it will use Arial:

We can also serve special content to users depending on the way fonts are rendered on their browser. We first create content for all three scenerios (browser uses font-smoothing, browser doesn’t use font-smoothing, and the “we cannot detect” case) and wrap the content inside <code>div</code> tags using appropriate CSS classes:

<div class="fontSmoothingMessage initiallyHidden">
<p>You browser <strong>is</strong> rendering this page
with font-smoothing. Because of that, we will attempt
to serve up the Droid Sans font to render this page,
because we think it looks cool. If you are using a
browser (such as Google Chrome) that cannot render
downloaded True Type fonts by default, then the page
will be rendered using Arial instead.</p>
</div>
<div class="noFontSmoothingMessage initiallyHidden">
Your browser <strong>is not</strong> rendering this
page with font-smoothing. It is for that reason we have
decided to use the plain old Arial font to render this
page, because it is hinted for use for displays that
don't employ a font-smoothing technology.
</div>
<div class="unknownFontSmoothingMessage initiallyHidden">
<strong>We are not sure</strong> if your browser is
rendering this page with a font-smoothing technology.
It is for that reason we have decided to use the plain
old Arial font to render this page, because it is
hinted for use for displays that don't employ a
font-smoothing technology.
</div>

Note all the div tags are members of the class initiallyHidden. This class will be used to hide all font-smoothing related content until the script kicks in.

This script cannot detect font-smoothing in any version of Opera (at the time of this writing, this includes all versions up to 10.10), since it cannot write text inside the canvas element in a way we can poll the pixels afterwards. If anyone can find a way of making it work with Opera, please write a comment below — I’d love to be able to support this browser.

Testing Caveats

Testing font-smoothing in most Windows web browsers is easy since it can be turned off inside the Display control panel. However, when using Safari for Windows, it is necessary to navigate inside Safari’s Appearance preferences and set the Font-smoothing option to Windows Standard. This is because by default, Safari uses it’s own built-in font-rendering engine which doesn’t seem to render aliased fonts. In Mac OS X, it seems anti-aliasing only works for fonts below a certain size, so aliased fonts don’t seem to be an issue with that operating system. In Ubuntu Linux I have yet to find a way of shutting of font-smoothing. If anyone knows a way, please let me know.

74 responses so far

The Active X approach would have identified ClearType in particular, but this approach seems to give a positive result with either choice, correct? I’d bet 90% of people with Font Smoothing enabled are using ClearType, so this distinction is mostly moot.

Paul: you are right – either ClearType or Standard font-smoothing will give a positive result. I believe that you are right that most Windows XP and above users use ClearType – I would love to see if there were any stats on that though.

One suggestion: In your Droid/Arial example, I’d change the CSS to let @font-face be the default, and switch to Arial only when smoothing is *not* enabled. My guess is most people will have smoothing enabled. Forcing them to wait for JS to execute will delay loading of @font-face, increasing the likelihood of seeing that dreaded flash of unstyled text when initially loading the font.

Philip: that is a great point – it’s what I was thinking when I was first drawing up that example, since I don’t like taking away functionality to JavaScript-disabled browsers if I can help it.

The problem was that sometimes, the script would kick in after the Droid font would load, causing the user to first see the Arial font, then the loaded Droid font, and then back to the Arial font again.

The question is: for the amount of users that this affects, is it really an issue, and should we have Droid load by default? I’m not sure. Maybe the right solution is to do a combination of this script and Paul Irish’s Anti-@font-face-FOUT script.

Zoltan,
Yes both Cleartype and Standard return positive in XP.
Clever script – BTW. Maybe someday browser makers will give scripters all the methods, properties, and events we need. Until then, we query for the info indirectly. I look at it like paying taxes.
Be aware that in FF 3.6 a new ability to smooth images in the Canvas tag is appearing.
Don’t know how that might impact this work. Just mentioning it.

After reading this I initially thought I could get around Opera’s lack of support for the canvas text API, but it doesn’t work either. Opera can draw SVG images to the canvas, so I thought I could just write an SVG image containing a rendering of the letter O in 32px Arial then pixel manipulate that. It wouldn’t work because of security violations for multiple reasons. One is that images whose source are Data URIs can’t be manipulated in the canvas. Additionally for some stupid reason SVG can’t be manipulated either, even using toDataURL(). Guess there’ll have to be a wait for Opera’s support for the canvas text API.

Thanks for doing the research on this issue, zoltan. This’ll bring us closer to unifying the way fonts are displayed across browsers and operating systems. These inconsistencies are the main reason why I don’t to make extensive use of custom fonts on websites. I made an attempt a while ago, but I was heavily disappointed after comparing the rendering between Windows and Mac, and I’m not even mentioning Linux (all using the same browser, Firefox).

Ace: it is for these reasons why we are promoting the Type Rendering Project! We hope to make this into a forum and discussion on how to make fonts look good on the web now. Hopefully this article is a good start in that direction.

@Agos: That’s intreresting. That would imply that either the iphone’s browser doesn’t support canvas, or that that fonts in canvas don’t render the same as in plain HTML. I’ll have to see if I can test on a friend’s iphone and update the routine. Thanks for letting me know – I’ll let you know when there is a fix.

Paul Irish told me about an Active X control that can do just that, but we discovered it wasn’t on every IE install. I don’t believe there is any way to detect a specific font-smoothing technology in the other browsers. :-/

Here’s how to disable font anti-aliasing in Gnome, if you haven’t found out yet:
Go to System > Preferences > Appearance. Click ‘Fonts’ and then select ‘Monochrome’ rendering. For more control over font rendering click the ‘Details…’ button.

@Matt Stow: If you change “32px Arial” to e.g. “12px Arial” in line 55 of TypeHelpers, it will only set “hasFontSmoothing-true” if ClearType is enabled. I suppose it would be easy to run a test at each font size to distinguish between none, Standard or ClearType.

This looks like something I should keep in mind. Currently I am using sIFR, but I will definitly give this a go. If I encounter something useful, I will let you know. Thanks for the time you took to figure this out!

Great article and even greater script. I recently combined the neccessary parts (at least as far as my rather uncomplete JavaScript knowledge allowed me to tell what was necessary) of EventHelpers.js with TypeHelpers.js and Paul Irish’s FOUT fighting script. The result is a 3 KB (only 1.3 KB with gzip) big JavaScript file which handles all of my Webfont loading problems. I use this combined script it on all my websites. (combined-script download and information here: http://www.michael-van-laar.de/blog/artikel/webfont-load-enhancer/ – Website only in German, readme.txt inside the zip file in English) Works great!

Of course I also included Lars G. Sehested’s “12px Arial” configuration tweak in the documentation of my combined script. You both are credited various times, so I hope my “set it and forget it” script solution is OK for you.

Perhaps some of you are aware that there are obvious differences in font rendering between standard and cleartype methods on XP. I use webfonts on a site that drives photo portofolios and these fonts anti alias perfectly when windows is using the standard method (antialiasing is monochrome in this case) Cleartype however(which is enabled by default in IE8, regardless of the system setting) however smooths most of these fonts in an uglier, jagged way, especially ar larger sizes :( I think Cleartype is default in Windows 7, and XP has as default the Standard method. I would rather use cleartype fonts, such as Corbel or Calibri if cleartype is enabled that a webfont that ends up looking worse.

>That would imply that [...] fonts in canvas don’t render the same as in plain HTML.

Regular text rendering will typically use subpixel rendering (ClearType and the like), but that won’t work inside a Canvas. Subpixel rendering isn’t a very good idea if the result might be transformed.

>ctx.getImageData(i, j, 1, 1)

It should be faster if you grab all 800 pixels at once. Even if you only check a few of them. The call itself is pretty expensive and the data doesn’t have much weight (relatively). Sorta like a cruiser ship with only one passenger. Doesn’t really matter if there are more of them.

This seems to be a great solution for me, but I’m curious about some details. I’m serving FF Meta to a site using Typekit, and it’s been looking horrible—near unreadable—on PC’s with font smoothing disabled. I’ve implemented your script, so I’m off to test it.

Is there any truth to this? Can your method detect font smoothing with IE?

Lastly, could you explain or provide a suggestion on how I would use jQuery instead of the EventHelpers.js? I’m a javascript newb, so excuse my ignorance, but I’m using this on a site that is already loading jQuery.

@Ira: The script first checks to see if screen.fontSmoothingEnabled is present (which is true only in IE). If it is present, it uses it to see if font-smoothing is on. If not, then it does the canvas check. screen.fontSmoothingEnabled is true if ClearType or “Standard” smoothing is on, so it should be a bulletproof test.

As for using jQuery instead of EventHelpers, this should be quite easily done. Just take out the if condition at the end of TypeHelpers.js and replace it with a call to $.ready(). This article should help a little.

@Jos: I am unsure about what you meant about your first comment, could you clarify? This algorithm does work in all the four canvas enabled desktop browsers, so I am not sure as to what you mean — I must be missing something.

As for the second comment, I was unaware how expensive the .getImageData() call is .. thanks for the tip. Will have to update this in a future release.

Still not sure about the jQuery solution, mostly because I’m not sure what EventHelpers is doing…and how to make jQuery do the same thing. I know how to use jQuery to get basic things done, it’s the more complicated stuff that I’m not sure about how to use it in this situation. I won’t bug you with it though…see if I can figure it out with some web sleuthing.

If you get all 800 pixels its only faster for browsers that fail, but your current method of getting pixels 1 at a time is faster for browsers that pass (which is now most browsers). This happens because to get find a semi-transparent pixel, you only need to make a few calls before it finds one (around 7-8 I think, can’t remember).

storing all 800 pixels (times the 4 RGBA values) is pretty slow, and only makes up for the speed when you access that data many many times.

@andy: It may be worth looking into this. The problem is there is a way to tune cleartype, so I can’t rely on “every Arial O has these colored pixels in the middle”. If you or anyone else has any ideas about how to work around this, I’m all ears.

Hi, first of all thanks for that your fontSmoothing detection is very cool. i have tested it a little bit and have seeen document.body.appendChild(canvasNode); is no longer needed in safari (win). if you kill this line you can fire the whole script in your head section and you do not have to wait for “dom ready”.

@Chris: ClearType is one of many types of anti-aliasing/font smoothing technologies out there and, as far as I know, only available on the Windows platform. In Windows XP, one can turn off font-smoothing completely, but in Windows Vista and Windows 7 it seems that one can only choose to use ClearType or “vanilla” font-smoothing. I believe this is because the fonts that come with Vista and higher (e.g. Consolas, Calibri, and a whole bunch of others that begin with the letter ‘C’) require font-smoothing or they look like crap.

I use the script for years now. It seems that since the last Google Chrome Update (Version: 17.0.963.79) the script has a problem with Chrome on Win7. It always comes to the (wrong) conclusion “hasFontSmoothing-false”. In IE 9 and FF everything works as a charm.

I have just come across your script – getting frustrated at how other people’s websites look to me (with no font smoothing). However when I tried your real life example it reported that I have font smoothing on – and I don’t (at least I don’t think I do).
I am on Win7 x64 using Firefox 11. I have cleartype off and I have edited the registry values to remove all font smoothing: [HKEY_CURRENT_USER\Control Panel\Desktop] FontSmoothing = 0 and FontSmoothingType = 0

Hi Zoltan,
first of all, thank you for this wonderfull skript!
Since a few weeks, I do have the same Problem like Michael mentioned in the post before.
I was wondering whether you will provide an fix for that issue.
Thank you!
Alex

@Alexander, @Michael: Sorry for the late reply — I must have missed these among all my other messages. When I check the script with Chrome 18, I don’t see any problems. Can you give me a URL to a page where this actually happens?

Any ideas how to tell GDI rendering apart from DirectWrite rendering on Windows Vista oder Windows 7?
IE9 does only DirectWrite, Firefox 4+ does use DirectWrite in some cases, Chrome does not at all (yet).

Tip: If you are implementing this on a rtl html (right to left, like hebrew and arabic), note that you have to set the canvas to stay in ltr, or the letter you draw get out of bounds (just add canvasNode.style.direction = “ltr”; when creating the canvas.) Just spent an hour figuring this out…

Give Feedback

Don't be shy! Give feedback and
join the discussion.

Please Note: If you are asking for help using the information on this page or if you are reporting a bug with the code featured here,
please include a URL that shows the problem you are experiencing along with the browser/version number/operating system
combination where the issue manifests itself. Without this information, I may not be able to respond.