6

I know you can get the font-family value by window.getComputedStyle() but that's not always exactly the font that is used by a browser to render. For example, if the given text contains the (multi-lingual) text the font family does not carry, the browser renders the text partially with the system font.

If you take a look at the built-in web developer tool, either in Chrome or Firefox, they both have a little area to display (Rendered Fonts pane on Chrome or Fonts tab on Firefox) the exact fonts that are used. For the Firefox, I guess this code is used and it seems to be calling the internal API.

I'm looking for any DOM-compliant (or vendor-specific) way to get the exact font from the JavaScript land or else. If that means writing a browser extension/add-on to provide API/inject info/whatever for the in-page code to access, that's the worst case, but acceptable.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
beatak
  • 9,185
  • 10
  • 33
  • 42
  • Juust out of curiosity, what is *"multilingual."*? What's the exact issue with it? How does that *Multilingual* messes with an element `font-family` computed style? (A font family is a font family, using you English or Chinese) – Roko C. Buljan Sep 29 '15 at 21:40
  • I say multilingual just because it's obvious. It won't mess with font-family. For example, like you say Chinese… If '好' appears in the text node that is set `courier` by css, the browser uses whatever system font. It's a browser, that does some extra work, and I want to know if that happens. – beatak Sep 29 '15 at 21:46

1 Answers1

1

You can with a hack : the main idea is to compare the size of inline elements with some given fonts. One should use the complete font-family value, another only a single font-family. Here's a proof of concept which work pretty well.

// Look at the fiddle for full working code
function createFontTester(fontFamily) {
  var container = document.createElement('div');
  var tester = document.createElement('div');

  container.style.position = 'absolute';
  container.style.overflow = 'auto';
  container.style.visibility = 'hidden';

  tester.style.fontFamily = fontFamily;
  tester.style.display = 'inline';
  tester.style.visibility = 'hidden';

  // The size should be big enough to make a visual difference
  tester.style.fontSize = '100px'; 

  // Reset and prevent line breaks
  tester.style.fontWeight = 'normal';
  tester.style.fontStyle = 'normal';
  tester.style.letterSpacing = 'normal';
  tester.style.lineHeight = 'normal';
  tester.style.whiteSpace = 'nowrap';

  document.body.appendChild(container);
  container.appendChild(tester);

  return tester;
}

Note that some fonts are so similar that most characters take the same space. Take Helvetica and Arial for instance : character width is mostly the same, height is slightly different so I used a large font-size.

This method is probably not bullet-proof but it work for every font-families I could think of.

Update : I've made this little library on Github which handle even more use cases.

  • If you're going to make a brute-force check, using canvas would be better IMO, first fillText() with the default font, then check the canvas imageData and finally compare it with all your fonts, but seriously, are you going to download all the fonts of the WWW for it? – Kaiido Oct 01 '15 at 03:53
  • I'm not downloading anything, what do you mean ? That said, the canvas idea is interesting. – Julien Cabanès Oct 01 '15 at 07:12
  • Maybe I'm misreading and if so I apologize, but your idea seems like a brute force to me, so you have to check for every font in the system. But, you can't get the list of all fonts available on system, so, in order to get some of them, you'll have to download them right? Like, on my browser, I do use the SourceCodePro font for monospace, your proof of concept only show me monospace, but default one is Courier on my system. OP's request is on the same order since he asked for CJK characters, default CJK fonts don't display the same set of chars and multiple fonts may be used for a single text – Kaiido Oct 01 '15 at 14:25
  • You are right: I can't list all available fonts (except with Flash I guess) so I don't. What I do is loop through each *single* font-family from font-family list and compare each one vs. the list. If size is different, it means fallback so not available. I can't find what's your default `monospace`, what I can *guess* is what's the browser's fallback. In your case, the POC can't show `Courier` because it's not in the declaration. If you have none of the font listed, the final fallback is `monospace` and it shows you exactly this, whether the real font behind is `Courier` or `SourceCodePro`. – Julien Cabanès Oct 01 '15 at 15:03