javascript - lista alla typsnitt som en användares webbläsare kan visa


Finns det ett sätt i JavaScript att få namnen på alla typsnitt (eller typsnittsfamiljer) som webbläsaren kan visa? (Jag vill ge användaren en rullgardinsmeny med en lista över alla tillgängliga typsnitt och låta användaren välja ett typsnitt.) Jag skulle föredra att inte behöva hårdkoda denna lista i förväg eller skicka den från servern. (Intuitivt verkar det som om webbläsaren borde veta vilka typsnitt den har och detta borde på något sätt vara tillgängligt för JavaScript.)

Svar #1

Ja, det finns! Jag är så glad att du ställde den här frågan eftersom jag nu också vill använda detta.

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

Kod från 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;
};

Sammanfattning

Hur fungerar det?

Den här koden fungerar på den enkla principen att varje tecken ser olika ut i olika typsnitt. Så olika typsnitt kommer att ta olika bredd och höjd för samma sträng av tecken i samma teckenstorlek.

Svar #2

2024 Uppdatering

Det FontFaceSet.check() som beskrivs nedan verkar nu vara "fixat" på Chrome så det fungerar inte längre.

  • Det finns dock nu ett lokalt teckensnittstillgångs-API
  • Ytterligare information finns här med en live-demonstration här
  • För närvarande är det bara Chrome och tyvärr ser det inte ut som att det kommer att förändras snart: Firefox, webkit.

Windows 10 teckensnittlista

'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 teckensnitt lista

'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() lösning

  • Att upptäcka alla tillgängliga typsnitt är en vanlig teknik för webbläsarfingeravtryck, så det är osannolikt att någon JS-API någonsin kommer att läggas till som direkt returnerar en lista.
  • Stödet för FontFaceSet.check() är tillräckligt bra för att användas men kommer att behöva en fallback, t.ex. detta svar för äldre webbläsare.
  • Att kontrollera följande lista med typsnitt tar över 150 ms, så det måste endast köras vid behov och resultatet bör cachas.

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()]);
})();

Svar #3

Det finns ett sätt att göra detta med document.fonts.

Det returnerade värdet är dokumentets FontFaceSet-gränssnitt. FontFaceSet-gränssnittet är användbart för att ladda nya typsnitt, kontrollera statusen för tidigare laddade typsnitt, etc.

  • Returnerade värden är utförliga med vikt, stil osv.
function listFonts() {
  return [...document.fonts.values()];
}
  • Returnerar endast teckensnittsfamiljen
function listFontFamilies() {
  const fontFaces = [...document.fonts.values()];
  const families = fontFaces.map(font => font.family);

  // converted to set then to array to remove duplicates
  return [...new Set(families)];
}

Jag har testat det utan att länka några typsnitt i HTML, sedan länkade jag Roboto-typsnittet, testade igen och det lades till i resultatet.

Svar #4

JavaScript-versionen är lite opålitlig. Den hämtar teckensnitt genom att gå igenom kända teckensnitt och testa dem.

Det mest exakta sättet (även om man måste använda ett proprietärt plugin) är att använda Flash. Här kan du få listan över typsnitt utan att behöva testa dem individuellt med hjälp av mått.

Du kommer att behöva besluta om du vill ha en exakt lista på bekostnad av att det inte fungerar på vissa enheter (iDevices, webbläsare utan Flash-plugin, etc.), eller en partiell lista med bättre stöd via enbart JavaScript.

Svar #5

Du kan använda det nya Local Font Access API för att enumerera igenom alla typsnitt:

console.log(await queryLocalFonts());

Du kan också kontrollera om användaren har gett tillstånd:

const {state} = await navigator.permissions.query({name: 'local-fonts'});

console.log(state); // Either 'granted', 'prompt' or 'denied'

Svar #6

Det korta svaret är. Inte mycket har förändrats när det gäller teckensnittsupptäckt i webbläsare under 2020 förutom att användning av Flash nu är en ännu sämre idé.

Det finns för närvarande inget webbläsarbaserat system för att "lista" alla tillgängliga typsnitt. Detta är avsiktligt för att undvika webbläsarspårning och dess säkerhetsimplikationer.

Däremot låter webbläsare dig kontrollera om ett typsnitt är laddat/klart med hjälp av FontFaceSet API. Det är ganska väl stödd i moderna webbläsare.

Detta är avsett att visa om ett webbtypsnitt är helt nedladdat MEN det fungerar även för systemtypsnitt. Fällan är att du måste tillhandahålla en lista över typsnitt att kontrollera.

Så i samband med ett user agent-test (inte alltid exakt), kan du ta fram en lista över vanliga systemteckensnitt för varje enhetstyp. Sedan testar du mot dessa och eventuella webbteckensnitt du laddar.

OBS: Detta kommer INTE att ge dig en fullständig lista över tillgängliga typsnitt, men du kan kontrollera typsnitt som vanligtvis är installerade av MS Office- eller Adobe-produkter.

Relaterade artiklar