views:

2325

answers:

14

Suppose I have the following CSS rule in my HTML.

body { font-family:Calibri,Trebuchet MS,Helvetica,sans-serif; }

How can I detect which one of the defined fonts was used in the user's browser?

Edit for people wondering why I want to do this: The font I am detecting contains glyphs not available in other fonts and when the user does not have it I want to display a link asking the user to download that font so they can use my web application.

Currently I am displaying the download font link for all users, now I can only display it for people who do not have the correct font installed.

+11  A: 

I've seen it done in a kind of iffy, but pretty reliable way. Basically, an element is set to use a specific font and a string is set to that element. If the font set for the element does not exist, it takes the font of the parent element. So, what they do is measure the width of the rendered string. If it matches what they expected for the desired font as opposed to the derived font, it's present.

Here's where it came from: ajaxian.com

MojoFilter
+2  A: 

I ran across this:

Javascript/CSS Font Detector

which lets you detect what fonts are available based on the size of fonts. From here you might be able to tell what font was loaded onto the page by using the same technique?

dragonmantank
+1  A: 

I agree with MojoFilter that this is your best bet. Obviously, you'd use the font-detector to see what fonts the user has installed, which would let you tell which of the font-family was applied.

Karl Seguin
A: 

One thing to keep in mind is that some browsers will replace certain missing fonts with similar fonts, which is impossible to detect using the JavaScript/CSS trick.

For example, Windows browsers will substitute Arial for Helvetica if it's not installed. The trick MojoFilter and dragonmatank mentioned will still report that Helvetica is installed, even though it isn't.

tlrobinson
A: 

Not to mention rendering of fonts is subtly different between different browsers and different versions of browsers, and probably depending on whether ClearType is turned on, and depending on various CSS font-rules (letter-spacing comes to mind) and so forth.

Now you can take the user's OS and deduce that X font is installed on that OS, but Calibri is still in its growth phase unfortunately.

James D
A: 

I'm trying to think of a nice way of putting this but I'm having an autistic day so forgive me if this comes across a little blunt.

Detecting of fonts in a browser is a lost cause. Why attempt to check the font when you can't even be sure a font of any kind is being used a device resorting to using the screen CSS might still be headless or a users personal styles might be overloading your stylesheet.

Any attempt to force a user to view a site in a particular way is doomed to fail so go with the flow.

sparkes
A: 

@sparkes

On the contrary your rant is well placed, but in my case the font I am detecting contains glyphs not available in other fonts and when the user does not have it I want to display a link asking the user to download it if they want to use the web app.

Currently I am displaying the download font link for all users, but I was looking for a way to hide it if they already have the needed font.

Pat
A: 

@Pat you say

On the contrary your rant is well placed, but in my case the font I am detecting contains glyphs not available in other fonts and when the user does not have it I want to display a link asking the user to download it if they want to use the web app.

If you are using Glyphs that don't have a meaning in the language used on your site then surely they should be images and explained using correctly formatted html.

sparkes
+1  A: 

A technique that works is to look at the computed style of the element. This is supported in Opera and Firefox (and I recon in safari, but haven't tested). IE (7 at least), provides a method to get a style, but it seems to be whatever was in the stylesheet, not the computed style. More details on quirksmode: http://www.quirksmode.org/dom/getstyles.html

Here's a simple function to grab the font used in an element:

/**
 * Get the font used for a given element
 * @argument {HTMLElement} the element to check font for
 * @returns {string} The name of the used font or null if font could not be detected
 */
function getFontForElement(ele) {
    if (ele.currentStyle) { // sort of, but not really, works in IE
        return ele.currentStyle["fontFamily"];
    } else if (document.defaultView) { // works in Opera and FF
        return document.defaultView.getComputedStyle(ele,null).getPropertyValue("font-family");
    } else {
        return null;
    }
}

If the CSS rule for this was:

#fonttester {
    font-family: sans-serif, arial, helvetica;
}

Then it should return helvetica if that is installed, if not, arial, and lastly, the name of the system default sans-serif font. Note that the ordering of fonts in your CSS declaration is significant.

An interesting hack you could also try is to create lots of hidden elements with lots of different fonts to try to detect which fonts are installed on a machine. I'm sure someone could make a nifty font statistics gathering page with this technique.

runeh
A: 

@runeh your method does not work.

The computed style will be "sans-serif, arial, helvetica" for the example you provided (I just tested your code to confirm)

Actually an easy way to verify this is using Firebug , inspect an element and then in the options chose "Show computed style" you'll see that the value is not the actual font that was used from the list.

Pat
A: 

@Pat

Seems you're right about firefox, which is weird because I'm sure I tested it. Opera does use the proper computed style, that is the font that is actually used. (not that that helps if you need it to work in IE/FF). Sounds like a firefox bug. Anyone with safari installed that can check what that browser does?

runeh
A: 

@runeh

You are right! Opera and Safari give the font used, while Firefox and IE give the rule used (which contains all the fonts).

However on my machine I noticed that Opera returns Arial While Safari returns Helvetica! Maybe Safari for windows does not use the system fonts, but its own.

Edit: See philoye'answer regarding Safari's behavior.

Pat
+1  A: 

A small note of caution: If you are offering a link to download Calibri, be aware that although it is bundled within several Microsoft products, it is not a free font, and you are breaching copyright by offering it for download.

Adam Hepton
+3  A: 

@pat Actually, Safari does not give the font used, Safari instead always returns the first font in the stack regardless of whether it is installed, at least in my experience.

    font-family: "my fake font", helvetica, san-serif;

Assuming Helvetica is the one installed/used, you'll get:

  • "my fake font" in Safari (and I believe other webkit browsers).
  • "my fake font, helvetica, san-serif" in Gecko browsers and IE.
  • "helvetica" in Opera 9, though I read that they are changing this in Opera 10 to match Gecko.

I took a pass at this problem and created Font Unstack, which tests each font in a stack and returns the first installed one only. It uses the trick that @MojoFilter mentions, but only returns the first one if multiple are installed. Though it does suffer from the weakness that @tlrobinson mentions (Windows will substitute Arial for Helvetica silently and report that Helvetica is installed), it otherwise works well.

github.com/philoye/fontunstack/tree/master

philoye
Thanks for the warning.
Pat