Listen Sie alle Schriftarten auf, die der Browser eines Benutzers anzeigen kann

104

Gibt es in Javascript eine Möglichkeit, die Namen aller Schriftarten (oder Schriftfamilien) abzurufen, die der Browser anzeigen kann? (Ich möchte dem Benutzer ein Dropdown-Menü mit einer Liste aller verfügbaren Schriftarten geben und dem Benutzer die Auswahl einer Schriftart ermöglichen.) Ich würde es vorziehen, diese Liste nicht vorab fest zu codieren oder vom Server herunterzusenden. (Intuitiv scheint es so, als ob der Browser wissen sollte, welche Schriftarten er hat, und dies sollte irgendwie Javascript ausgesetzt sein.)

mattsh
quelle

Antworten:

37

Die JavaScript-Version ist etwas schuppig. Es erhält Schriftarten, indem es bekannte Schriftarten durchläuft und testet.

Der genaueste Weg (obwohl ein Propriety-Plugin verwendet werden muss) ist die Verwendung von Flash . Hier können Sie die Liste der Schriftarten abrufen, ohne sie einzeln anhand von Abmessungen testen zu müssen.

Sie müssen sich entscheiden, ob Sie eine genaue Liste auf Kosten einiger nicht funktionierender Geräte (iDevices, Browser ohne Flash-Plugin usw.) oder eine Teilliste mit besserer Unterstützung nur über JavaScript erstellen möchten .

Alex
quelle
29
@ Jared Für die Erwähnung von Flash? Ich habe nicht gesagt, dass dies die einzige Lösung ist. Ich habe erwähnt, dass dies die genaueste Methode zum Erkennen von Schriftarten ist.
Alex
4
@alex Ja. Dies könnte Entwicklern den falschen Eindruck vermitteln, insbesondere neuen. Ich schlage vor, Ihre Antwort zu bearbeiten, um die Vor- und Nachteile der Verwendung von Flash besser zu erklären, vielleicht nur "Es wird nicht empfohlen, aber ..." oder so ähnlich.
Jared
19
@Jared Muss ich alle meine Antworten schreiben, um den Lesern Informationen von Grund auf zur Verfügung zu stellen, wenn sie neu im Handwerk sind? Ich habe zwar erklärt, dass für Flash ein Propriety-Plugin erforderlich ist, aber ich habe auch erwähnt, dass dies derzeit die einzige Möglichkeit ist, alle verfügbaren Schriftarten abzurufen (die JavaScript-Methode erkennt nur eine Teilmenge von Schriftarten, was für die meisten Anwendungsfälle wahrscheinlich gut genug ist). Ich bin auch nicht glücklich darüber, Flash verwenden zu müssen, aber es ist alles, was wir derzeit für diese Aufgabe haben.
Alex
7
@ Jared Sehen Sie den letzten Absatz? Vielleicht möchten Sie es noch einmal lesen.
Alex
10
@ Jared Dieser Absatz existierte immer.
Alex
73

Ja da ist! Ich bin so froh, dass Sie diese Frage gestellt haben, weil ich sie jetzt auch verwenden möchte.

+1 für Frage, und hier ist deine Antwort :)

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

Code von 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;
};

Zusammenfassung

Wie funktioniert es?

Dieser Code basiert auf dem einfachen Prinzip, dass jedes Zeichen in verschiedenen Schriftarten unterschiedlich angezeigt wird. Unterschiedliche Schriftarten benötigen also unterschiedliche Breite und Höhe für dieselbe Zeichenfolge mit derselben Schriftgröße.

Marko
quelle
2
Sehr hinterhältig. Das ist fantastisch.
rekursiv
4
Vielen Dank, ja, dies ist nützlich, wenn ich eine Liste von Schriftarten habe, um zu testen, was installiert ist, aber das Problem ist, wie man zuerst eine Liste von Schriftnamen generiert.
Mattsh
43
Dies gibt nur ein Ja / Nein dafür, ob eine Schriftart installiert ist.
rektide
2
Zuerst fand ich es großartig, aber dann habe ich einige Probleme gefunden. Das Hauptproblem ist, dass jeder Browser unterschiedliche Ergebnisse zurückgibt. Auf jeden Fall nicht zuverlässig.
Błażej Klisz
11
Interessant und nützlich, beantwortet aber die Frage nicht. Dadurch werden die Namen der im Browser verfügbaren Schriftarten nicht abgerufen. Widerstrebend -1 geben.
Benjamin
7

Es gibt eine Möglichkeit, dies mit zu tun document.fonts

Der zurückgegebene Wert ist die FontFaceSet-Schnittstelle des Dokuments. Die FontFaceSet-Oberfläche ist nützlich zum Laden neuer Schriftarten, zum Überprüfen des Status zuvor geladener Schriftarten usw.

  • Die zurückgegebenen Werte sind ausführlich mit Gewicht, Stil usw.
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;
}
  • Gibt nur die Schriftfamilie zurück
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)];
}

Ich habe es getestet, ohne irgendwelche Schriftarten im HTML zu verknüpfen, dann die Roboto-Schrift verknüpft, erneut getestet und es wurde zum Ergebnis hinzugefügt.

Youssef AbouEgla
quelle
5
<SCRIPT>
    function getFonts()
    {
        var nFontLen = dlgHelper.fonts.count;
        var rgFonts = new Array();
        for ( var i = 1; i < nFontLen + 1; i++ )
            rgFonts[i] = dlgHelper.fonts(i); 

        rgFonts.sort();
        for ( var j = 0; j < nFontLen; j++ )
            document.write( rgFonts[j] + "<BR>" );
    }
</SCRIPT>

<BODY onload="getFonts()">
<OBJECT id=dlgHelper CLASSID="clsid:3050f819-98b5-11cf-bb82-00aa00bdce0b" width="0px" height="0px">
</OBJECT>
MPC
quelle
2
@ Robert Sköld, ja, es scheint nur IE zu sein. Es ist immer noch für viele Zwecke nützlich. Wenn Sie es jedoch ernsthaft verwenden, sollten Sie über eine Funktionserkennung verfügen, damit Benutzer anderer Browser dies verstehen. siehe zB cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela
Es wird nicht in IE11 für Windows Phone funktionieren? Gibt es noch etwas, das ich für Windows Phone hinzufügen muss?
Jats
3

Bei meiner Suche danach habe ich auch Font.js gefunden , das ein Font-Objekt ähnlich wie Image hinzufügt, sodass überprüft werden kann, wann eine Schriftart tatsächlich einsatzbereit ist. Funktioniert auch mit installierten / System-Schriftarten. Nachteil ist IE9 + nur aufgrund der Notwendigkeit Object.defineProperty(andere Browser haben es), aber wenn Sie modernes Web tun, scheint dies eine noch bessere Option zu sein. (Ich werde leider mit der obigen Antwort weitermachen müssen, positiv bewertet und vorerst weitermachen. :))

Stoffe
quelle
3

Ich habe oben zwei Methoden zu Lalit Patels Detektor hinzugefügt:

  • addFont (family, stylesheetUrl, ruleString) -> erkennt, ob die Schriftfamilie 'family' vorhanden ist, wenn nicht, fügt ein Stylesheet hinzu, das die Schriftart entweder mit stylesheetUrl lädt, falls angegeben, oder anderweitig mit ruleString
  • addFontsArr (arr) -> fügt ein Array von Schriftarten hinzu

Damit können Sie tun:

fonts = [ 'Arial', 'Arial Black', { family: 'Lato', stylesheetUrl: 'https://fonts.googleapis.com/css?family=Lato'}, 'Leelawadee UI']
(new FontDetector()).addFontsArr(fonts);

Code:

/**
 * 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');
 */
function FontDetector() {
    this.detect = detect;
    this.addFont = addFont;
    this.addFontsArr = addFontsArr;

    // 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;
    }

    function addFont(family, stylesheetUrl, ruleString) {
        if (detect(family)) {
            //console.log('using internal font '+family);
            return true;
        }
        if (stylesheetUrl) {
            console.log('added stylesheet '+stylesheetUrl);
            var head = document.head, link = document.createElement('link');
            link.type = 'text/css';
            link.rel = 'stylesheet';
            link.href = stylesheetUrl;
            head.appendChild(link);
            return true;          
        }

        if (ruleString) {
            console.log('adding font rule:'+rule);
            var newStyle = document.createElement('style');
            newStyle.appendChild(document.createTextNode(rule));
            document.head.appendChild(newStyle);
            return true;
        }

        console.log('could not add font '+family);
    }

    function addFontsArr(arr) {
        arr.forEach(a => typeof a==='string' ? addFont(a) : addFont(a.family, a.stylesheetUrl, a.ruleString));
    }
};
Kofifus
quelle
3

FontFaceSet.check () Lösung

  • Das Erkennen aller verfügbaren Schriftarten ist eine gängige Fingerabdruckmethode für Browser. Daher ist es unwahrscheinlich, dass jemals eine JS-API hinzugefügt wird, die direkt eine Liste zurückgibt.
  • Die Unterstützung von FontFaceSet.check () ist gut genug, um verwendet zu werden, benötigt jedoch einen Fallback, z. B. diese Antwort für ältere Browser.
  • Das Überprüfen der folgenden Liste von Schriftarten dauert mehr als 150 ms und muss daher nur nach Bedarf ausgeführt und das Ergebnis zwischengespeichert werden.

Windows 10-Schriftartenliste

'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-Schriftartenliste

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

chris
quelle
danke, das ist es, wonach ich auch für eventuelles Webdesign entlang lokaler Systemschriftarten suche, um viel Flexibilität beim Anzeigen von Inhalten oder Parsen von Seiten zu erlangen, um nicht viel CPU zu füllen
Constantin
2

Möglicherweise könnte dies auf eine ganz andere Art und Weise geschehen, indem ein Spritesheet mit bekannten Schriftbildern für ein bestimmtes Zeichen verwendet und dieses mit Schnappschüssen eines Canvas-Elements verglichen wird, auf dem dasselbe Zeichen gezeichnet wird, mit dem, was der Browser als dieselbe Schriftart meldet. Der Vergleich kann mit so etwas wie resemble.js durchgeführt werden .

Dies ist langsamer, sollte es uns aber auch ermöglichen, zu erkennen, wann der Browser lügt.

fzzylogic
quelle
2

Die kurze Antwort lautet. An der Erkennung von Schriftarten in Browsern im Jahr 2020 hat sich nicht viel geändert, außer dass die Verwendung von Flash jetzt eine noch schlechtere Idee ist .

Derzeit gibt es kein natives Browser-System, um alle verfügbaren Schriftarten aufzulisten. Mit Browsern können Sie jedoch mithilfe der FontFaceSet-API überprüfen, ob eine Schriftart geladen / bereit ist . Es wird in modernen Browsern ziemlich gut unterstützt.

Dies soll zeigen, ob eine Webschrift vollständig heruntergeladen wurde, aber auch für Systemschriftarten funktioniert. Der Haken ist, dass Sie eine Liste der zu überprüfenden Schriftarten bereitstellen müssen .

In Verbindung mit einem user agent Test (nicht immer genau) können Sie eine Liste gängiger Systemschriftarten erstellen für jeden Gerätetyp . Testen Sie dann diese und alle von Ihnen geladenen Web-Schriftarten.

HINWEIS: Dadurch erhalten Sie KEINE vollständige Liste der verfügbaren Schriftarten. Sie können jedoch nach Schriftarten suchen, die üblicherweise von MS Office- oder Adobe-Produkten installiert werden.

Bryce Howitson
quelle
0

Ich habe kürzlich festgestellt, dass die Änderung von der Zeichenfläche ignoriert wird, wenn ich den Wert context.font für eine HTML5-Zeichenfläche auf etwas Ungültiges wie "Junk" setze. Ich weiß nicht, ob dies browserspezifisch ist, aber es scheint auf Chrome so zu funktionieren. Ich habe auch andere Beiträge gesehen ( HTML 5-Canvas-Schrift wird ignoriert ), die darauf hinweisen, dass dies in anderen Browsern geschieht.

Man könnte dann eine Zeichenfolge mit dem Standardwert "10px sans serif" ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ) ausschreiben und die Schriftart festlegen zu einem testen Sie und schreiben den String erneut. Wenn es mit der ersten Zeichnung identisch ist, ist die Schriftart nicht verfügbar.

AFF
quelle