list every font a user's browser can display
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.
Related videos on Youtube
mattsh
Updated on July 08, 2022Comments
-
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 almost 14 yearsVery devious. This is awesome.
-
Faisal almost 14 years+1. I just saw this the other day, too...definitely very cool. :D
-
mattsh over 13 yearsThank 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 almost 13 yearsThis will only give a yes/no for whether a font is installed.
-
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 over 11 yearsHere 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 about 11 yearsFirst 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 about 11 yearsWhy would you rollback the edit? I was removing the noise outside of the actual answer.
-
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 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 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 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 almost 11 years@Marko Posting fluff around a link also adds nothing to the answer. :)
-
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 almost 11 yearsWhat 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 almost 11 years@Jared See that last paragraph? You may wish to read it again.
-
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 almost 11 years@Jared That paragraph always existed.
-
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 over 10 yearsWhile 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 about 10 yearslink is broken: Error establishing a database connection
-
Marko about 10 yearsSorry 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 about 10 yearsEhm, 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 over 9 yearsIt will not work in IE11 for windows phone??is there anything else i need to add for windows phone???
-
BenjaminGolder almost 9 yearsInteresting 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 about 8 years@jared Just compared the dates and times. Your statement evaluates to "You are blind".
-
Dawied almost 8 yearsThanks for mentioning Flash, it is still the only solution for determining available fonts.
-
1.21 gigawatts about 7 yearsFlash 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 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 about 7 yearsIt 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 about 7 yearsYeah I get that, but I wonder if it's identifying enough to concern the user. The user already sends user agent, IP, etc
-
Jacksonkr about 7 yearsNow 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 almost 4 yearsthanks 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 over 3 yearsthis 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 over 3 yearswhen I run this in Firefox, it only shows web fonts (like FontAwesome)
-
Trade-Ideas Philip over 3 yearsOn 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 over 3 yearsoutdated now, i guess
-
Hikariztw over 3 yearsConsider 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 about 3 yearsThis works, it should be the accepted answer. Thanks.
-
DenverCoder9 almost 3 yearsThe 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 viafor (const metadata of pickedFonts) { }
. The article has been updated accordingly. -
I wrestled a bear once. almost 3 yearsLooks like it's only showing fonts that are downloaded from the server.
-
Sharjeel Faiq about 2 yearsCan 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?