lista wszystkich czcionek, które przeglądarka użytkownika może wyświetlić

105

Czy w javascript jest sposób na uzyskanie nazw wszystkich czcionek (lub rodzin czcionek), które może wyświetlić przeglądarka? (Chcę udostępnić użytkownikowi listę rozwijaną z listą wszystkich dostępnych czcionek i pozwolić użytkownikowi wybrać czcionkę.) Wolałbym nie musieć zakodować tej listy na stałe z wyprzedzeniem ani wysyłać jej z serwera. (Intuicyjnie wydaje się, że przeglądarka powinna wiedzieć, jakie ma czcionki i powinno to jakoś zostać ujawnione w javascript).

mattsh
źródło

Odpowiedzi:

37

Wersja JavaScript jest nieco niestabilna. Pobiera czcionki, przechodząc przez znane czcionki i testując.

Najdokładniejszym sposobem (choć trzeba użyć odpowiedniej wtyczki) jest użycie Flasha . Tutaj możesz uzyskać listę czcionek bez konieczności testowania ich indywidualnie za pomocą wymiarów.

Będziesz musiał zdecydować, czy chcesz mieć dokładną listę kosztem braku działania na niektórych urządzeniach (iDevices, przeglądarki bez wtyczki Flash itp.), Czy też częściową listę z lepszą obsługą tylko przez JavaScript .

Alex
źródło
30
@Jared Za wspomnienie o Flashu? Nie powiedziałem, że to jedyne rozwiązanie, wspomniałem, że to najdokładniejszy sposób wykrywania czcionek.
Alex
4
@alex Yes. Może to zrobić złe wrażenie deweloperom, zwłaszcza nowym. Proponuję zredagować swoją odpowiedź, aby lepiej wyjaśnić zalety i wady korzystania z Flasha, może po prostu „Nie jest zalecane, ale ...” lub coś w tym rodzaju.
Jared,
19
@Jared Czy muszę pisać wszystkie swoje odpowiedzi, aby przekazać informacje od podstaw dla czytelników, jeśli są nowicjuszami w tej dziedzinie? Wyjaśniłem, że Flash wymaga odpowiedniej wtyczki, ale wspomniałem również, że jest to obecnie jedyny sposób na uzyskanie wszystkich dostępnych czcionek (metoda JavaScript tylko wykrywa podzbiór czcionek, co prawdopodobnie jest wystarczające dla większości przypadków użycia). Nie jestem też zadowolony, że muszę używać Flasha, ale to wszystko, co mamy teraz do tego zadania.
Alex
7
@Jared Widzisz ten ostatni akapit? Możesz przeczytać ją ponownie.
Alex
10
@Jared Ten akapit istniał zawsze.
Alex
74

Tak jest! Tak się cieszę, że zadałeś to pytanie, ponieważ teraz chcę też tego użyć.

+1 na pytanie, a oto Twoja odpowiedź :)

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

Kod z 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;
};

Podsumowanie

Jak to działa?

Ten kod działa na prostej zasadzie, że każdy znak pojawia się inaczej w różnych czcionkach. Dlatego różne czcionki będą miały różną szerokość i wysokość dla tego samego ciągu znaków o tym samym rozmiarze czcionki.

Marko
źródło
2
Bardzo przebiegły. To jest niesamowite.
rekurencyjne
4
Dziękuję, tak, jest to przydatne, gdy mam listę czcionek, aby przetestować, co jest zainstalowane, ale problem polega na tym, jak w pierwszej kolejności wygenerować listę nazw czcionek.
mattsh
44
To da tylko odpowiedź tak / nie, czy czcionka jest zainstalowana.
powtórz
2
Najpierw pomyślałem, że to świetne, ale potem znalazłem kilka problemów. Główny problem polega na tym, że każda przeglądarka zwraca inne wyniki. Zdecydowanie nie jest wiarygodne.
Błażej Klisz
11
Ciekawe i przydatne, ale nie odpowiada na pytanie. Nie powoduje to pobrania nazw czcionek dostępnych w przeglądarce. Dając niechętnie -1.
BenjaminGolder
12

Można to zrobić za pomocą document.fonts

Zwracana wartość to interfejs FontFaceSet dokumentu. Interfejs FontFaceSet jest przydatny do ładowania nowych czcionek, sprawdzania stanu wcześniej załadowanych czcionek itp.

  • Zwracane wartości są szczegółowe z wagą, stylem itp.
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;
}
  • Zwraca tylko rodzinę czcionek
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)];
}

Przetestowałem to bez łączenia żadnych czcionek w HTML, następnie podłączyłem czcionkę Roboto, przetestowałem ponownie i został dodany do wyniku.

Youssef AbouEgla
źródło
ten fragment kodu działał idealnie, dzięki! `` `` 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; }} // przekonwertowane na zestaw, a następnie arr do filtru powtarzających się wartości return [... new Set (arr)]; } ``
rufreakde
kiedy uruchamiam to w przeglądarce Firefox, wyświetla tylko czcionki internetowe (takie jak FontAwesome)
Tim Davis
6

Rozwiązanie FontFaceSet.check ()

  • Wykrywanie wszystkich dostępnych czcionek jest powszechną techniką pobierania odcisków palców przeglądarki , więc jest mało prawdopodobne, aby kiedykolwiek dodano API JS, które bezpośrednio zwróci listę.
  • Obsługa FontFaceSet.check () jest wystarczająco dobra, aby z niej korzystać, ale będzie potrzebować rozwiązania zastępczego, np. Tej odpowiedzi dla starszych przeglądarek.
  • Sprawdzenie poniższej listy czcionek zajmuje ponad 150 ms, więc należy je uruchamiać tylko w razie potrzeby, a wynik przechowywać w pamięci podręcznej.

Lista czcionek systemu 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',

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

chris
źródło
dzięki tego też szukam do ewentualnego projektowania stron internetowych wraz z lokalnymi czcionkami systemowymi, aby uzyskać dużą wiarygodność w wyświetlaniu treści lub analizowaniu strony w taki sposób, aby nie wypełniać dużo procesora
Constantin
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>
RPP
źródło
2
@Robert Sköld, tak, wygląda na to, że dotyczy tylko przeglądarki IE. Nadal jest przydatny do wielu celów, ale gdy jest używany poważnie, powinieneś mieć pewne funkcje wykrywania, aby ludzie używający innych przeglądarek zrozumieli; patrz np. cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela
To nie będzie działać w IE11 dla Windows Phone? Czy jest coś jeszcze, co muszę dodać do Windows Phone?
jats
4

Dodałem dwie metody do detektora Lalit Patel powyżej:

  • addFont (family, stylesheetUrl, ruleString) -> wykrywa, czy istnieje `` rodzina '' czcionki, jeśli nie, dodaje arkusz stylów ładując czcionkę za pomocą stylesheetUrl, jeśli podano, lub w inny sposób ruleString
  • addFontsArr (arr) -> dodaje tablicę czcionek

Dzięki temu możesz:

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

kod:

/**
 * 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
źródło
3

Szukając tego, znalazłem również Font.js , który dodaje obiekt Font podobnie jak Image, dzięki czemu można sprawdzić, kiedy czcionka jest rzeczywiście gotowa do użycia. Działa również na czcionkach zainstalowanych / systemowych. Wadą jest IE9 + tylko ze względu na potrzebę Object.defineProperty(inne przeglądarki go mają), ale jeśli robisz nowoczesną sieć, wydaje się to jeszcze lepszą opcją. (Niestety, będę musiał odpowiedzieć na powyższe pytanie, przegłosowałem i na razie idę dalej. :))

Stoffe
źródło
3

Krótka odpowiedź brzmi. Niewiele się zmieniło w zakresie wykrywania czcionek w przeglądarkach w 2020 roku, poza tym, że używanie Flasha jest teraz jeszcze gorszym pomysłem .

Obecnie nie ma natywnego systemu przeglądarki, który mógłby „wyświetlić” wszystkie dostępne czcionki. Jednak przeglądarki umożliwiają sprawdzenie, czy czcionka jest załadowana / gotowa za pomocą interfejsu API FontFaceSet . Jest całkiem dobrze obsługiwany w nowoczesnych przeglądarkach.

Ma to na celu pokazanie, czy czcionka internetowa została całkowicie pobrana, ALE będzie działać również w przypadku czcionek systemowych. Problem polega na tym, że musisz podać listę czcionek do sprawdzenia.

Zatem w połączeniu z user agent testem (nie zawsze dokładnym) można stworzyć listę typowych czcionek systemowych dla każdego typu urządzenia. Następnie przetestuj te i wszystkie ładowane czcionki internetowe.

UWAGA: NIE da ci to pełnej listy dostępnych czcionek, ale możesz sprawdzić czcionki powszechnie instalowane przez produkty MS Office lub Adobe.

Bryce Howitson
źródło
2

Może można by to zrobić w zupełnie inny sposób, używając arkusza sprites ze znanymi obrazami czcionek dla określonej postaci i porównując to z migawkami elementu płótna, na którym ten sam znak jest rysowany za pomocą tego, co przeglądarka zgłasza jako tę samą czcionkę. Porównanie można wykonać za pomocą czegoś takiego jak resemble.js .

Jest to wolniejsze, ale powinno również pozwolić nam wykryć, kiedy przeglądarka kłamie.

fzzylogic
źródło
0

Niedawno zauważyłem, że jeśli ustawię wartość context.font dla płótna HTML5 na coś nieprawidłowego, na przykład „śmieci”, zmiana zostanie zignorowana przez płótno. Nie wiem, czy to jest specyficzne dla przeglądarki, ale wydaje się, że działa w ten sposób w Chrome. Widziałem również inne posty ( ignorowanie czcionki płótna HTML 5 ), które wskazują, że dzieje się to w innych przeglądarkach.

Następnie można napisać ciąg znaków z wartością domyślną, którą uważam za „10px sans serif” ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ), ustawić czcionkę do tego, który testujesz, i ponownie napisz ciąg. Jeśli jest taki sam jak pierwszy rysunek, czcionka nie jest dostępna.

AFF
źródło