Guessing font availability with Javascript
Posted on 13 November 2008 (09:28 PM)
Recently I wanted to use an uncommon font in a website, but the site was too image-rich to use sIFR, (loading time made for an uneasy user experience).
I decided to add the font anyway in my stylesheet, and provide a “lo-fi” experience, for people who didn’t have the font handy.
The lo-fi version however, should mimic the style of the uncommon font as good as possible.
Sometimes, though, that’s easier said than done.
The problem
The font in question was Copperplate Gothic Light. I had chosen the classic Times New Roman as my backup font (playing it safe), but Times in no way mimics Copperplate.
The only similarity between the two fonts is the fact that they’re both Serifs.
In order for me to make Times look like Copperplate, I had to at least display the text in small-caps.
This is where the first obstacle presented itself: using CSS, I cannot specify a different font-variant for my number one choice than for my fall-back font.
Consider this piece of CSS:
h2 {font-family: “Copperplate Gothic Light”, “Times New Roman”;font-size: 13px;}- Download this code: /code/guessing_font_availability_with_javascript1.txt
If I would specify font-variant: small-caps;, my text would be displayed in small-caps regardless of which font the user sees. In this particular case that’s no big deal, because Copperplate Gothic Light displays in caps anyway, but let’s say Copperplate renders a bit bigger than Times. In that case I would like to be able to specify a larger font-size in the case where Copperplate would be absent.
I decided I needed another styling hook on which to base style rules. In the event of a user not having Copperplate installed, I would use a class on the BODY element of “alt-font”.
The accompanying CSS rules would look like this:
h2 {font-family: “Copperplate Gothic Light”;font-size: 13px;}body.alt-font h2 {font-family: “Times New Roman”;font-size: 14px;font-variant: small-caps;}- Download this code: /code/guessing_font_availability_with_javascript2.txt
But how to decide when to add that class name to the BODY?
An educated guess
I wrote a little Javascript function that does the guesswork for me. The guessFontAvailability function looks like this:
function guessFontAvailability (desiredFont) {// create an element with the desired font familyvar a = document.createElement ('span');a.appendChild (document.createTextNode ('AAA'));a.style.fontFamily = desiredFont + ', monospace';a.style.fontSize = '100px';a.style.visibility = 'hidden';// create an element which will use the browser's default monospace fontvar b = document.createElement ('span');b.appendChild (document.createTextNode ('AAA'));b.style.fontFamily = 'monospace';b.style.fontSize = '100px';b.style.visibility = 'hidden';// attach the elements to the bodydocument.body.appendChild (a);document.body.appendChild (b);// check if the dimensions of the elements are similarvar available = true;if (a.offsetWidth === b.offsetWidth &&a.offsetHeight === b.offsetHeight) {available = false;}// remove the elements and return the availability of the fonta.parentNode.removeChild (a);b.parentNode.removeChild (b);return available;}- Download this code: /code/guessing_font_availability_with_javascript3.txt
This function returns a simple true or false based on a guess about a font’s availability. It works like this:
if (!guessFontAvailability (‘Copperplate Gothic Light’)) {// if the font is not available, provide an alternative styling hookdocument.body.className += ‘ alt-font’;}- Download this code: /code/guessing_font_availability_with_javascript4.txt
How does it work? I’ll walk you through it:
var a = document.createElement ('span');a.appendChild (document.createTextNode ('AAA'));a.style.fontFamily = desiredFont + ', monospace';a.style.fontSize = '100px';a.style.visibility = 'hidden';- Download this code: /code/guessing_font_availability_with_javascript5.txt
First, a SPAN element is created, containing some text that’ll be rendered in either the desired font, or the browser’s default monospace font.
var b = document.createElement ('span');b.appendChild (document.createTextNode ('AAA'));b.style.fontFamily = 'monospace';b.style.fontSize = '100px';b.style.visibility = 'hidden';- Download this code: /code/guessing_font_availability_with_javascript6.txt
Second, I create another SPAN element, which renders in the browser’s default monospace font regardless of the desired font’s availibility.
Note that on both elements the visibility property is set to hidden, so users will never notice my little guess.
document.body.appendChild (a);document.body.appendChild (b);// check if the dimensions of the elements are similarvar available = true;if (a.offsetWidth === b.offsetWidth &&a.offsetHeight === b.offsetHeight) {available = false;}- Download this code: /code/guessing_font_availability_with_javascript7.txt
After adding both SPAN elements to the BODY, I check their dimensions. If both the width and the height are the same, the elements are probably both rendered in the browser’s default monospace font. If not, they must be different and therefore there’s a good chance the desired font is available.
Last but not least, I remove the elements from the DOM again:
a.parentNode.removeChild (a);b.parentNode.removeChild (b);return available;- Download this code: /code/guessing_font_availability_with_javascript8.txt
Caution!
Please note that the script only guesses. If your desired font accidentally has the same dimensions as the browser’s default monospace font, the function will think the font is not available. But this is probably something you should think about on a per-case basis.
Do you think this script is useful or rubbish? Let me know in the comments! Also, if you know of any improvements, leave a comment and I might write a second version.
Filed under HTML and CSS, Javascript
- ← previous article: Making the most of Javascript namespacing
- → next article: Hello Amsterdam!
Comments:
Very Interesting - After reading the title I guessed the approach youn would take - I suppose it's the only way though.
It would be cool to set up a test page that compares various fonts so you could see how many (if any) common ones provide false results.