list every font a user's browser can display

79,398

Solution 1

The JavaScript version is a bit flaky. It gets fonts by iterating through known fonts and testing.

The most accurate way (albeit having to use a propriety plugin) is to use Flash. Here you can get the list of fonts without having to test for them individually using dimensions.

You are going have to decide whether to have an exact list at the expense of not working on some devices ( iDevices, browsers without Flash plugin, etc), or a partial list with better support via JavaScript only.

Solution 2

Yes there is! I'm so glad you asked this question because I now want to use this too.

http://www.lalit.org/lab/javascript-css-font-detect

Code from http://www.lalit.org/wordpress/wp-content/uploads/2008/05/fontdetect.js?ver=0.3

/**
 * JavaScript code to detect available availability of a
 * particular font in a browser using JavaScript and CSS.
 *
 * Author : Lalit Patel
 * Website: http://www.lalit.org/lab/javascript-css-font-detect/
 * License: Apache Software License 2.0
 *          http://www.apache.org/licenses/LICENSE-2.0
 * Version: 0.15 (21 Sep 2009)
 *          Changed comparision font to default from sans-default-default,
 *          as in FF3.0 font of child element didn't fallback
 *          to parent element if the font is missing.
 * Version: 0.2 (04 Mar 2012)
 *          Comparing font against all the 3 generic font families ie,
 *          'monospace', 'sans-serif' and 'sans'. If it doesn't match all 3
 *          then that font is 100% not available in the system
 * Version: 0.3 (24 Mar 2012)
 *          Replaced sans with serif in the list of baseFonts
 */

/**
 * Usage: d = new Detector();
 *        d.detect('font name');
 */
var Detector = function() {
    // a font will be compared against all the three default fonts.
    // and if it doesn't match all 3 then that font is not available.
    var baseFonts = ['monospace', 'sans-serif', 'serif'];

    //we use m or w because these two characters take up the maximum width.
    // And we use a LLi so that the same matching fonts can get separated
    var testString = "mmmmmmmmmmlli";

    //we test using 72px font size, we may use any size. I guess larger the better.
    var testSize = '72px';

    var h = document.getElementsByTagName("body")[0];

    // create a SPAN in the document to get the width of the text we use to test
    var s = document.createElement("span");
    s.style.fontSize = testSize;
    s.innerHTML = testString;
    var defaultWidth = {};
    var defaultHeight = {};
    for (var index in baseFonts) {
        //get the default width for the three base fonts
        s.style.fontFamily = baseFonts[index];
        h.appendChild(s);
        defaultWidth[baseFonts[index]] = s.offsetWidth; //width for the default font
        defaultHeight[baseFonts[index]] = s.offsetHeight; //height for the defualt font
        h.removeChild(s);
    }

    function detect(font) {
        var detected = false;
        for (var index in baseFonts) {
            s.style.fontFamily = font + ',' + baseFonts[index]; // name of the font along with the base font for fallback.
            h.appendChild(s);
            var matched = (s.offsetWidth != defaultWidth[baseFonts[index]] || s.offsetHeight != defaultHeight[baseFonts[index]]);
            h.removeChild(s);
            detected = detected || matched;
        }
        return detected;
    }

    this.detect = detect;
};

Summary

How does it work?

This code works on the simple principle that each character appears differently in different fonts. So different fonts will take different width and height for the same string of characters of same font-size.

Solution 3

There is a way to do this using document.fonts

The returned value is the FontFaceSet interface of the document. The FontFaceSet interface is useful for loading new fonts, checking the status of previously loaded fonts, etc.

  • Returned values are verbose with weight, style, etc.
function listFonts() {
  let { fonts } = document;
  const it = fonts.entries();

  let arr = [];
  let done = false;

  while (!done) {
    const font = it.next();
    if (!font.done) {
      arr.push(font.value[0]);
    } else {
      done = font.done;
    }
  }

  return arr;
}
  • Returns only the font family
function listFonts() {
  let { fonts } = document;
  const it = fonts.entries();

  let arr = [];
  let done = false;

  while (!done) {
    const font = it.next();
    if (!font.done) {
      arr.push(font.value[0].family);
    } else {
      done = font.done;
    }
  }

  // converted to set then arr to filter repetitive values
  return [...new Set(arr)];
}

I have tested it without linking any fonts in the HTML, then linked Roboto font, tested again and it got added to the result.

Solution 4

FontFaceSet.check() solution

  • Detecting all available fonts is common browser fingerprinting technique so it is unlikely any JS API will ever be added which will directly return a list.
  • FontFaceSet.check() support is good enough to be used but will need a fallback e.g. this answer for older browsers.
  • Checking the following list of fonts takes 150ms+ so will need to be run only as required and the result cached.

Windows 10 Font List

'Arial',
'Arial Black',
'Bahnschrift',
'Calibri',
'Cambria',
'Cambria Math',
'Candara',
'Comic Sans MS',
'Consolas',
'Constantia',
'Corbel',
'Courier New',
'Ebrima',
'Franklin Gothic Medium',
'Gabriola',
'Gadugi',
'Georgia',
'HoloLens MDL2 Assets',
'Impact',
'Ink Free',
'Javanese Text',
'Leelawadee UI',
'Lucida Console',
'Lucida Sans Unicode',
'Malgun Gothic',
'Marlett',
'Microsoft Himalaya',
'Microsoft JhengHei',
'Microsoft New Tai Lue',
'Microsoft PhagsPa',
'Microsoft Sans Serif',
'Microsoft Tai Le',
'Microsoft YaHei',
'Microsoft Yi Baiti',
'MingLiU-ExtB',
'Mongolian Baiti',
'MS Gothic',
'MV Boli',
'Myanmar Text',
'Nirmala UI',
'Palatino Linotype',
'Segoe MDL2 Assets',
'Segoe Print',
'Segoe Script',
'Segoe UI',
'Segoe UI Historic',
'Segoe UI Emoji',
'Segoe UI Symbol',
'SimSun',
'Sitka',
'Sylfaen',
'Symbol',
'Tahoma',
'Times New Roman',
'Trebuchet MS',
'Verdana',
'Webdings',
'Wingdings',
'Yu Gothic',

macOS/iOS Font List

'American Typewriter',
'Andale Mono',
'Arial',
'Arial Black',
'Arial Narrow',
'Arial Rounded MT Bold',
'Arial Unicode MS',
'Avenir',
'Avenir Next',
'Avenir Next Condensed',
'Baskerville',
'Big Caslon',
'Bodoni 72',
'Bodoni 72 Oldstyle',
'Bodoni 72 Smallcaps',
'Bradley Hand',
'Brush Script MT',
'Chalkboard',
'Chalkboard SE',
'Chalkduster',
'Charter',
'Cochin',
'Comic Sans MS',
'Copperplate',
'Courier',
'Courier New',
'Didot',
'DIN Alternate',
'DIN Condensed',
'Futura',
'Geneva',
'Georgia',
'Gill Sans',
'Helvetica',
'Helvetica Neue',
'Herculanum',
'Hoefler Text',
'Impact',
'Lucida Grande',
'Luminari',
'Marker Felt',
'Menlo',
'Microsoft Sans Serif',
'Monaco',
'Noteworthy',
'Optima',
'Palatino',
'Papyrus',
'Phosphate',
'Rockwell',
'Savoye LET',
'SignPainter',
'Skia',
'Snell Roundhand',
'Tahoma',
'Times',
'Times New Roman',
'Trattatello',
'Trebuchet MS',
'Verdana',
'Zapfino',

FontFaceSet.check()

const fontCheck = new Set([
  // Windows 10
'Arial', 'Arial Black', 'Bahnschrift', 'Calibri', 'Cambria', 'Cambria Math', 'Candara', 'Comic Sans MS', 'Consolas', 'Constantia', 'Corbel', 'Courier New', 'Ebrima', 'Franklin Gothic Medium', 'Gabriola', 'Gadugi', 'Georgia', 'HoloLens MDL2 Assets', 'Impact', 'Ink Free', 'Javanese Text', 'Leelawadee UI', 'Lucida Console', 'Lucida Sans Unicode', 'Malgun Gothic', 'Marlett', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Sans Serif', 'Microsoft Tai Le', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU-ExtB', 'Mongolian Baiti', 'MS Gothic', 'MV Boli', 'Myanmar Text', 'Nirmala UI', 'Palatino Linotype', 'Segoe MDL2 Assets', 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Historic', 'Segoe UI Emoji', 'Segoe UI Symbol', 'SimSun', 'Sitka', 'Sylfaen', 'Symbol', 'Tahoma', 'Times New Roman', 'Trebuchet MS', 'Verdana', 'Webdings', 'Wingdings', 'Yu Gothic',
  // macOS
  'American Typewriter', 'Andale Mono', 'Arial', 'Arial Black', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', 'Avenir', 'Avenir Next', 'Avenir Next Condensed', 'Baskerville', 'Big Caslon', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bradley Hand', 'Brush Script MT', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charter', 'Cochin', 'Comic Sans MS', 'Copperplate', 'Courier', 'Courier New', 'Didot', 'DIN Alternate', 'DIN Condensed', 'Futura', 'Geneva', 'Georgia', 'Gill Sans', 'Helvetica', 'Helvetica Neue', 'Herculanum', 'Hoefler Text', 'Impact', 'Lucida Grande', 'Luminari', 'Marker Felt', 'Menlo', 'Microsoft Sans Serif', 'Monaco', 'Noteworthy', 'Optima', 'Palatino', 'Papyrus', 'Phosphate', 'Rockwell', 'Savoye LET', 'SignPainter', 'Skia', 'Snell Roundhand', 'Tahoma', 'Times', 'Times New Roman', 'Trattatello', 'Trebuchet MS', 'Verdana', 'Zapfino',
].sort());

(async() => {
  await document.fonts.ready;

  const fontAvailable = new Set();

  for (const font of fontCheck.values()) {
    if (document.fonts.check(`12px "${font}"`)) {
      fontAvailable.add(font);
    }
  }

  console.log('Available Fonts:', [...fontAvailable.values()]);
})();

Solution 5

The short answer is. Not much has changed regarding fonts detection in browsers in 2020 except that using Flash is now an even worse idea.

There's currently no browser native system to "list" all available fonts. However, browsers will let you check if a font is loaded/ready using the FontFaceSet API. It's pretty well supported in modern browsers.

This is intended to show if a web font is completely downloaded BUT it will work for system fonts as well. The catch is you have to provide a list of fonts to check.

So in conjunction with a user agent test (not always accurate), you could produce a list of common system fonts for each device type. Then test against those and any web fonts you load.

NOTE: This will NOT give you a full list of available fonts, but you can check for fonts commonly installed by MS Office or Adobe products.

Share:
79,398

Related videos on Youtube

mattsh
Author by

mattsh

Updated on July 08, 2022

Comments

  • mattsh
    mattsh almost 2 years

    Is there a way in javascript to obtain the names of all fonts (or font-families) that the browser can show? (I want to give the user a dropdown with a list of all available fonts, and allow the user to choose a font.) I'd prefer not to have to hardcode this list ahead of time or send it down from the server. (Intuitively, it seems like the browser should know what fonts it has and this should be exposed to javascript somehow.)

  • B Bulfin
    B Bulfin almost 14 years
    Very devious. This is awesome.
  • Faisal
    Faisal almost 14 years
    +1. I just saw this the other day, too...definitely very cool. :D
  • mattsh
    mattsh over 13 years
    Thank you, yes this is useful once I have a list of fonts to test what is installed, but the problem is how to generate a list of font names in the first place.
  • rektide
    rektide almost 13 years
    This will only give a yes/no for whether a font is installed.
  • Jukka K. Korpela
    Jukka K. Korpela almost 12 years
    @Robert Sköld, yes, it appears to be IE-only. It’s still useful for many purposes, though when used seriously, you should have some feature detection so that people using other browsers will understand; see e.g. cs.tut.fi/~jkorpela/listfonts1.html
  • Dylan Valade
    Dylan Valade over 11 years
    Here is a Flash + JS and displays sample text with your fonts, which is what I was looking for. github.com/gabriel/font-detect-js
  • Błażej Klisz
    Błażej Klisz about 11 years
    First I thought it’s great but then I’ve found some issues. The main problem is that each browser returns different results. Definitely not reliable.
  • user3167101
    user3167101 about 11 years
    Why would you rollback the edit? I was removing the noise outside of the actual answer.
  • Marko
    Marko about 11 years
    @alex, because posting just a link as an answer is in my eyes insufficient and vague. I don't see anything wrong with the text.
  • user3167101
    user3167101 almost 11 years
    @Jared For mentioning Flash? I didn't say it was the only solution, I mentioned it's the most accurate way of detecting fonts.
  • Jared
    Jared almost 11 years
    @alex Yes. It might give the wrong impression to developers, especially new ones. I suggest editing your answer to better explain the pros and cons of using Flash, maybe just "It's not recommended, but..." or something like that.
  • user3167101
    user3167101 almost 11 years
    @Jared Do I need to write all my answers to provide information from the ground up for readers in the chance they are new to the craft? I did explain that Flash requires a propriety plugin, but I also mentioned it's currently the only way to get all available fonts (the JavaScript method just detects a subset of fonts, which is probably good enough for most use cases). I'm not happy about having to use Flash either, but it's all we have right now for this task.
  • user3167101
    user3167101 almost 11 years
    @Marko Posting fluff around a link also adds nothing to the answer. :)
  • Jared
    Jared almost 11 years
    @alex Yes? At least mention if it's the right or wrong thing to do. Just a word or two. It doesn't take much effort and helps newbies.
  • Jared
    Jared almost 11 years
    What happens if a newbie uses Flash to do this and they get an influx of complaints from iOS users? You could help them out now by instead of making them go back to SO to ask why it's not working, probably resulting in a duplicate question.
  • user3167101
    user3167101 almost 11 years
    @Jared See that last paragraph? You may wish to read it again.
  • Jared
    Jared almost 11 years
    @alex Thanks. I know it's painful to do so, but I believe it'll help in the long term. Back to +1.
  • user3167101
    user3167101 almost 11 years
    @Jared That paragraph always existed.
  • Jared
    Jared almost 11 years
    @alex Although the answer revisions says otherwise, I did not see that paragraph when I started this debate. Either you are a wizard and edited the revision notes or I'm blind.
  • João dos Reis
    João dos Reis over 10 years
    While I'm a big proponent of not using Flash, I think when you say it's dead, you're confusing it with the state of the guy who said it's dead. isflashdeadyet.com
  • Grom S
    Grom S about 10 years
    link is broken: Error establishing a database connection
  • Marko
    Marko about 10 years
    Sorry guys, looks like link has gone dead. Answer is 4 years old so I guess not many surprises. I should've copied some of the content and attributed to the author but from memory, it was lengthy.
  • Mr Lister
    Mr Lister about 10 years
    Ehm, the link isn't dead. Maybe the server was down when you tried just then. Nice article, by the way; I can use that.
  • jats
    jats over 9 years
    It will not work in IE11 for windows phone??is there anything else i need to add for windows phone???
  • BenjaminGolder
    BenjaminGolder almost 9 years
    Interesting and useful but does not answer the question. This does not retrieve the names of fonts available in the browser. Giving a reluctant -1.
  • oxygen
    oxygen about 8 years
    @jared Just compared the dates and times. Your statement evaluates to "You are blind".
  • Dawied
    Dawied almost 8 years
    Thanks for mentioning Flash, it is still the only solution for determining available fonts.
  • 1.21 gigawatts
    1.21 gigawatts about 7 years
    Flash Player will list all the fonts but of course the player is unavailable on mobile. My opinion is font listing should be behind an access prompt in Flash Player & should be made available to JavaScript via access prompt similar to the notifications prompt, web cam prompt and location prompt.
  • user3167101
    user3167101 about 7 years
    @1.21gigawatts It would be nice, perhaps confusing for an average user though This website wants to know which fonts are available on your system.
  • 1.21 gigawatts
    1.21 gigawatts about 7 years
    It might not make sense but the reason for the prompt is because it's identifying information. For word processors, graphic applications, spreadsheets (google docs) the prompt would make more sense since it's an advantage to provide the user with a list of his own fonts. I can't see it being used often but it's a way for JS developers to get that information if they need it rather than not at all.
  • user3167101
    user3167101 about 7 years
    Yeah I get that, but I wonder if it's identifying enough to concern the user. The user already sends user agent, IP, etc
  • Jacksonkr
    Jacksonkr about 7 years
    Now that SVG font rendering has been out for a while I'm sure you can replace your "flash" reference with an html5 / SVG solution.
  • Constantin
    Constantin almost 4 years
    thanks this is what i looking for too for eventual web design along local system fonts for gaining much fiability in showing content or parsing page in manner to not fill much cpu
  • rufreakde
    rufreakde over 3 years
    this code snippet worked perfectly thanks! ``` listFonts() { let fonts = document['fonts']; const it = fonts.entries(); let arr = []; let done = false; while (!done) { const font = it.next(); if (!font.done) { arr.push(font.value[0].family); } else { done = font.done; } } // converted to set then arr to filter repetitive values return [...new Set(arr)]; } ```
  • Tim Davis
    Tim Davis over 3 years
    when I run this in Firefox, it only shows web fonts (like FontAwesome)
  • Trade-Ideas Philip
    Trade-Ideas Philip over 3 years
    On Chome (in console for this page!) I ran Array.from(document.fonts) and I got two fonts, bot in the "Roboto Slab" family. Clearly I have more than those 2 fonts installed on my machine.
  • ashleedawg
    ashleedawg over 3 years
    outdated now, i guess
  • Hikariztw
    Hikariztw over 3 years
    Consider a "Chinese Japanese Korean" font, some of them might use the exactly same English font as their alphabet font face. Which seems to pass this test against different font set.
  • Really Nice Code
    Really Nice Code about 3 years
    This works, it should be the accepted answer. Thanks.
  • DenverCoder9
    DenverCoder9 almost 3 years
    The shape of the API has now changed slightly, it's a picker now that you access via const pickedFonts = await navigator.fonts.query() and whose picked options you can then iterate over via for (const metadata of pickedFonts) { }. The article has been updated accordingly.
  • I wrestled a bear once.
    I wrestled a bear once. almost 3 years
    Looks like it's only showing fonts that are downloaded from the server.
  • Sharjeel Faiq
    Sharjeel Faiq about 2 years
    Can you tell me how to use this in react js to get all the available fonts displayed in a dropdown which can be used to change the font of text inside textarea?