elenca tutti i caratteri che il browser di un utente può visualizzare


105

Esiste un modo in javascript per ottenere i nomi di tutti i caratteri (o famiglie di caratteri) che il browser può mostrare? (Voglio fornire all'utente un elenco a discesa con un elenco di tutti i caratteri disponibili e consentire all'utente di scegliere un carattere.) Preferirei non dover codificare questo elenco in anticipo o inviarlo dal server. (Intuitivamente, sembra che il browser dovrebbe sapere quali caratteri ha e questo dovrebbe essere esposto a javascript in qualche modo.)

Risposte:


38

La versione JavaScript è un po 'instabile. Ottiene i caratteri iterando attraverso caratteri noti e test.

Il modo più accurato (anche se è necessario utilizzare un plug-in di proprietà) è utilizzare Flash . Qui puoi ottenere l'elenco dei caratteri senza doverli testare singolarmente utilizzando le dimensioni.

Dovrai decidere se avere un elenco esatto a scapito di non funzionare su alcuni dispositivi (iDevices, browser senza plug-in Flash, ecc.) O un elenco parziale con un supporto migliore solo tramite JavaScript .


30
@ Jared per aver menzionato Flash? Non ho detto che fosse l'unica soluzione, ho detto che è il modo più accurato per rilevare i caratteri.
alex

4
@alex Sì. Potrebbe dare un'impressione sbagliata agli sviluppatori, specialmente a quelli nuovi. Suggerisco di modificare la tua risposta per spiegare meglio i pro e i contro dell'utilizzo di Flash, magari semplicemente "Non è consigliato, ma ..." o qualcosa del genere.
Jared

19
@ Jared Devo scrivere tutte le mie risposte per fornire informazioni da zero ai lettori nel caso in cui siano nuovi nel mestiere? Ho spiegato che Flash richiede un plug-in di proprietà, ma ho anche detto che attualmente è l'unico modo per ottenere tutti i caratteri disponibili (il metodo JavaScript rileva solo un sottoinsieme di caratteri, che è probabilmente abbastanza buono per la maggior parte dei casi d'uso). Nemmeno io sono contento di dover usare Flash, ma è tutto ciò che abbiamo per questo compito.
alex

7
@ Jared Vedi l'ultimo paragrafo? Potresti leggerlo di nuovo.
alex

10
@ Jared Quel paragrafo è sempre esistito.
alex

73

Si C'è! Sono così felice che tu abbia posto questa domanda perché ora voglio usare anche questa.

+1 per la domanda, ed ecco la tua risposta :)

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

Codice da 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;
};

Sommario

Come funziona?

Questo codice funziona sul semplice principio che ogni carattere appare in modo diverso in caratteri diversi. Quindi caratteri diversi avranno larghezza e altezza diverse per la stessa stringa di caratteri della stessa dimensione del carattere.


2
Molto subdolo. Questo e spettacolare.
ricorsivo

4
Grazie, sì, è utile una volta che ho un elenco di caratteri per testare ciò che è installato, ma il problema è come generare un elenco di nomi di caratteri in primo luogo.
mattsh

43
Questo darà solo un sì / no per se un font è installato.
rektide

2
All'inizio ho pensato che fosse fantastico, ma poi ho riscontrato alcuni problemi. Il problema principale è che ogni browser restituisce risultati diversi. Sicuramente non affidabile.
Błażej Klisz

11
Interessante e utile ma non risponde alla domanda. Ciò non recupera i nomi dei caratteri disponibili nel browser. Dando un riluttante -1.
BenjaminGolder

10

C'è un modo per farlo usando document.fonts

Il valore restituito è l'interfaccia FontFaceSet del documento. L'interfaccia FontFaceSet è utile per caricare nuovi caratteri, controllare lo stato dei caratteri caricati in precedenza, ecc.

  • I valori restituiti sono dettagliati con peso, stile, ecc.
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;
}
  • Restituisce solo la famiglia di caratteri
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)];
}

L'ho testato senza collegare alcun font nell'HTML, poi ho collegato il font Roboto, l'ho testato di nuovo e è stato aggiunto al risultato.


questo frammento di codice ha funzionato perfettamente grazie! `` `listFonts () {let fonts = document ['fonts']; const it = fonts.entries (); let arr = []; lasciare fatto = falso; while (! fatto) {const font = it.next (); if (! font.done) {arr.push (font.value [0] .family); } altro {fatto = font.done; }} // convertito in set poi arr per filtrare i valori ripetitivi return [... new Set (arr)]; } ``
rufreakde

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>

2
@Robert Sköld, sì, sembra essere solo IE. È ancora utile per molti scopi, anche se se usato seriamente, dovresti avere alcune funzionalità di rilevamento in modo che le persone che utilizzano altri browser possano capire; vedere ad esempio cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela

Non funzionerà in IE11 per Windows Phone ?? c'è qualcos'altro che devo aggiungere per Windows Phone ???
jats

4

Soluzione FontFaceSet.check ()

  • Il rilevamento di tutti i caratteri disponibili è una tecnica comune di fingerprinting del browser , quindi è improbabile che venga mai aggiunta un'API JS che restituirà direttamente un elenco.
  • Il supporto di FontFaceSet.check () è abbastanza buono da essere utilizzato ma avrà bisogno di un fallback, ad esempio questa risposta per i browser meno recenti.
  • Il controllo del seguente elenco di caratteri richiede 150 ms +, quindi dovrà essere eseguito solo come richiesto e il risultato memorizzato nella cache.

Elenco dei caratteri di 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',

Elenco caratteri macOS / iOS

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


grazie questo è quello che cerco anche io per un eventuale web design lungo i font di sistema locale per ottenere molta affidabilità nel mostrare il contenuto o analizzare la pagina in modo da non riempire molta CPU
Constantin

3

Nella mia ricerca di questo, ho anche trovato Font.js , che aggiunge un oggetto Font molto simile a Image, quindi è possibile controllare quando un font è effettivamente pronto per l'uso. Funziona anche su font installati / di sistema. Il rovescio della medaglia è IE9 + solo a causa della necessità Object.defineProperty(altri browser ce l'hanno), ma se stai facendo il web moderno, questa sembra un'opzione ancora migliore. (Purtroppo, dovrò accettare la risposta sopra, votata positivamente e per ora andare avanti. :))


3

Ho aggiunto due metodi al rilevatore di Lalit Patel sopra:

  • addFont (family, stylesheetUrl, ruleString) -> rileva se il font 'family' esiste, in caso contrario aggiunge un foglio di stile caricando il font usando uno stylesheetUrl se fornito o altrimenti ruleString
  • addFontsArr (arr) -> aggiunge un array di caratteri

Con questo puoi fare:

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

codice:

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

2

Forse questo potrebbe essere fatto in un modo completamente diverso, utilizzando uno spritesheet con immagini di font note per un carattere specifico e confrontandolo con le istantanee di un elemento canvas su cui è disegnato lo stesso carattere con ciò che il browser riporta come lo stesso font. Il confronto può essere fatto con qualcosa come resemble.js .

È più lento, ma dovrebbe anche permetterci di rilevare quando il browser mente.


2

La risposta breve è. Non è cambiato molto per quanto riguarda il rilevamento dei caratteri nei browser nel 2020, tranne per il fatto che l'utilizzo di Flash è ora un'idea ancora peggiore .

Al momento non esiste un sistema nativo del browser per "elencare" tutti i caratteri disponibili. Tuttavia, i browser ti consentono di controllare se un carattere è caricato / pronto utilizzando l' API FontFaceSet . È abbastanza ben supportato nei browser moderni.

Questo ha lo scopo di mostrare se un font web è stato completamente scaricato MA funzionerà anche per i font di sistema. Il problema è che devi fornire un elenco di caratteri da controllare.

Quindi, insieme a un user agent test (non sempre accurato), potresti produrre un elenco di caratteri di sistema comuni per ogni tipo di dispositivo. Quindi prova contro quelli e tutti i caratteri web che carichi.

NOTA: questo NON ti fornirà un elenco completo dei caratteri disponibili, ma puoi verificare i caratteri comunemente installati dai prodotti MS Office o Adobe.


0

Recentemente ho notato che se imposto il valore context.font per una tela HTML5, su qualcosa di non valido, come "spazzatura", la modifica viene ignorata dalla tela. Non so se questo sia specifico del browser, ma sembra funzionare in questo modo su Chrome. Ho anche visto altri post (il carattere HTML 5 canvas viene ignorato ) che indicano che accade in altri browser.

Si potrebbe quindi scrivere una stringa con il valore predefinito, che credo sia "10px sans serif" ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ), impostare il carattere a quello che stai testando e scrivi di nuovo la stringa. Se è uguale al primo disegno, il carattere non è disponibile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.