buat daftar setiap font yang dapat ditampilkan browser pengguna

105

Apakah ada cara dalam javascript untuk mendapatkan nama semua font (atau font-family) yang dapat ditampilkan oleh browser? (Saya ingin memberikan dropdown kepada pengguna dengan daftar semua font yang tersedia, dan mengizinkan pengguna untuk memilih font.) Saya lebih suka untuk tidak melakukan hardcode daftar ini sebelumnya atau mengirimkannya dari server. (Secara intuitif, sepertinya browser harus tahu font apa yang dimilikinya dan ini harus diekspos ke javascript.)

mattsh
sumber

Jawaban:

37

Versi JavaScript agak tidak stabil. Itu mendapat font dengan mengulang melalui font dan pengujian yang dikenal.

Cara paling akurat (meskipun harus menggunakan plugin yang sesuai) adalah dengan menggunakan Flash . Di sini Anda bisa mendapatkan daftar font tanpa harus mengujinya satu per satu menggunakan dimensi.

Anda harus memutuskan apakah akan memiliki daftar yang tepat dengan mengorbankan tidak berfungsi pada beberapa perangkat (iDevices, browser tanpa plugin Flash, dll), atau daftar parsial dengan dukungan yang lebih baik hanya melalui JavaScript .

alex
sumber
30
@ Jared Untuk menyebutkan Flash? Saya tidak mengatakan itu satu-satunya solusi, saya sebutkan itu cara paling akurat untuk mendeteksi font.
alex
4
@ex Ya. Hal tersebut mungkin saja memberikan kesan yang salah kepada developer, terutama yang baru. Saya sarankan untuk mengedit jawaban Anda untuk menjelaskan pro dan kontra penggunaan Flash dengan lebih baik, mungkin hanya "Ini tidak disarankan, tapi ..." atau sesuatu seperti itu.
Jared
19
@Jared Apakah saya perlu menulis semua jawaban saya untuk memberikan informasi dari bawah ke atas bagi pembaca jika mereka baru mengenal kerajinan? Saya memang menjelaskan bahwa Flash memerlukan plugin yang sesuai, tetapi saya juga menyebutkan bahwa saat ini itu satu-satunya cara untuk mendapatkan semua font yang tersedia (metode JavaScript hanya mendeteksi subset font, yang mungkin cukup baik untuk sebagian besar kasus penggunaan). Saya juga tidak senang harus menggunakan Flash, tetapi hanya itu yang kami miliki sekarang untuk tugas ini.
alex
7
@Jared Lihat paragraf terakhir itu? Anda mungkin ingin membacanya lagi.
alex
10
@Jared Paragraf itu selalu ada.
alex
74

Ya ada! Saya sangat senang Anda menanyakan pertanyaan ini karena sekarang saya ingin menggunakan ini juga.

+1 untuk pertanyaan, dan inilah jawaban Anda :)

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

Kode dari 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;
};

Ringkasan

Bagaimana cara kerjanya?

Kode ini bekerja dengan prinsip sederhana bahwa setiap karakter muncul secara berbeda dalam font yang berbeda. Jadi font yang berbeda akan mengambil lebar dan tinggi yang berbeda untuk string karakter yang sama dengan ukuran font yang sama.

Marko
sumber
2
Sangat licik. Ini luar biasa.
rekursif
4
Terima kasih, ya ini berguna setelah saya memiliki daftar font untuk menguji apa yang diinstal, tetapi masalahnya adalah bagaimana membuat daftar nama font di tempat pertama.
mattsh
44
Ini hanya akan memberikan ya / tidak untuk mengetahui apakah font telah diinstal.
rektide
2
Pertama saya pikir itu bagus tapi kemudian saya menemukan beberapa masalah. Masalah utamanya adalah setiap browser memberikan hasil yang berbeda. Jelas tidak bisa diandalkan.
Błażej Klisz
11
Menarik dan bermanfaat tapi tidak menjawab pertanyaan itu. Ini tidak mengambil nama font yang tersedia di browser. Memberi enggan -1.
BenjaminGolder
12

Ada cara untuk melakukan ini dengan menggunakan document.fonts

Nilai yang dikembalikan adalah antarmuka FontFaceSet dokumen. Antarmuka FontFaceSet berguna untuk memuat font baru, memeriksa status font yang dimuat sebelumnya, dll.

  • Nilai yang dikembalikan bertele-tele dengan bobot, gaya, dll.
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;
}
  • Hanya mengembalikan jenis font
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)];
}

Saya telah mengujinya tanpa menautkan font apa pun di HTML, lalu menautkan font Roboto, menguji lagi dan itu ditambahkan ke hasil.

Youssef AbouEgla
sumber
potongan kode ini bekerja dengan sempurna, terima kasih! `` `listFonts () {biarkan font = dokumen ['font']; const it = fonts.entries (); biarkan arr = []; biarkan selesai = salah; while (! done) {const font = it.next (); if (! font.done) {arr.push (font.value [0] .family); } lain {selesai = font.done; }} // dikonversi menjadi set kemudian arr untuk memfilter nilai berulang return [... new Set (arr)]; } ``
rufreakde
ketika saya menjalankan ini di Firefox, itu hanya menampilkan font web (seperti FontAwesome)
Tim Davis
6

Solusi FontFaceSet.check ()

  • Mendeteksi semua font yang tersedia adalah teknik sidik jari browser yang umum sehingga tidak mungkin ada JS API yang akan ditambahkan yang secara langsung akan mengembalikan daftar.
  • Dukungan FontFaceSet.check () cukup baik untuk digunakan tetapi akan membutuhkan fallback misalnya jawaban ini untuk browser lama.
  • Memeriksa daftar font berikut membutuhkan 150ms + jadi perlu dijalankan hanya jika diperlukan dan hasilnya di-cache.

Daftar Font 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',

Daftar Font 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
sumber
terima kasih, inilah yang saya cari juga untuk desain web akhirnya bersama font sistem lokal untuk mendapatkan banyak kemampuan dalam menampilkan konten atau halaman parsing dengan cara untuk tidak mengisi banyak cpu
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>
MPC
sumber
2
@Robert Sköld, ya, tampaknya hanya untuk IE. Ini masih berguna untuk banyak tujuan, meskipun jika digunakan dengan serius, Anda harus memiliki beberapa fitur deteksi sehingga orang yang menggunakan browser lain akan mengerti; lihat misalnya cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela
Ini tidak akan berfungsi di IE11 untuk windows phone ?? adakah hal lain yang perlu saya tambahkan untuk windows phone ???
jats
4

Saya menambahkan dua metode ke Detektor Lalit Patel di atas:

  • addFont (family, stylesheetUrl, ruleString) -> mendeteksi jika font 'family' ada, jika tidak menambahkan stylesheet memuat font menggunakan salah satu stylesheetUrl jika diberikan atau sebaliknya ruleString
  • addFontsArr (arr) -> menambahkan array font

Dengan ini, Anda dapat melakukan:

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

kode:

/**
 * 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.dll
sumber
3

Dalam pencarian saya untuk ini, saya juga menemukan Font.js , yang menambahkan objek Font seperti Image, jadi mungkin untuk memeriksa kapan font benar-benar siap digunakan. Juga berfungsi pada font terinstal / sistem. Kelemahannya adalah IE9 + hanya karena membutuhkan Object.defineProperty(browser lain memilikinya), tetapi jika Anda menggunakan web modern, ini sepertinya pilihan yang lebih baik. (Saya akan, sayangnya, harus melanjutkan dengan jawaban di atas, mendapat suara positif dan melanjutkan untuk saat ini. :))

Stoffe
sumber
3

Jawaban singkatnya adalah. Tidak banyak yang berubah terkait deteksi font di browser pada tahun 2020 kecuali bahwa menggunakan Flash sekarang merupakan ide yang lebih buruk .

Saat ini tidak ada sistem asli browser untuk "mencantumkan" semua font yang tersedia. Namun, browser akan membiarkan Anda memeriksa apakah font telah dimuat / siap menggunakan API FontFaceSet . Ini didukung dengan cukup baik di browser modern.

Ini dimaksudkan untuk menunjukkan apakah font web telah diunduh sepenuhnya TETAPI itu akan berfungsi untuk font sistem juga. Tangkapannya adalah Anda harus memberikan daftar font untuk diperiksa.

Jadi sehubungan dengan user agent pengujian (tidak selalu akurat), Anda dapat membuat daftar font sistem umum untuk setiap jenis perangkat. Kemudian uji terhadap itu dan font web apa pun yang Anda muat.

CATATAN: Ini TIDAK akan memberi Anda daftar lengkap font yang tersedia, tetapi Anda dapat memeriksa font yang biasa diinstal oleh produk MS Office atau Adobe.

Bryce Howitson
sumber
2

Mungkin ini bisa dilakukan dengan cara yang sama sekali berbeda, menggunakan spritesheet dengan gambar font yang diketahui untuk karakter tertentu dan membandingkannya dengan snapshot dari elemen kanvas di mana karakter yang sama digambar dengan apa yang dilaporkan browser sebagai font yang sama. Perbandingan dapat dilakukan dengan sesuatu seperti menyerupai js .

Ini lebih lambat, tetapi juga memungkinkan kami untuk mendeteksi saat browser berbohong.

fzzylogic.dll
sumber
0

Saya baru-baru ini memperhatikan bahwa jika saya menyetel nilai context.font untuk kanvas HTML5, ke sesuatu yang tidak valid, seperti "sampah", perubahan tersebut diabaikan oleh kanvas. Saya tidak tahu apakah ini khusus browser, tetapi tampaknya berfungsi seperti ini di Chrome. Saya juga melihat posting lain ( font kanvas HTML 5 diabaikan ) yang menunjukkan itu terjadi di browser lain.

Seseorang kemudian dapat menulis string dengan nilai default, yang saya yakini adalah "10px sans serif" ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ), mengatur font ke salah satu yang Anda uji dan tulis string lagi. Jika sama dengan gambar pertama, maka font tidak tersedia.

AFF
sumber