перелічити кожен шрифт, який може відображати браузер користувача


105

Чи існує спосіб у javascript отримати імена всіх шрифтів (або сімейств шрифтів), які браузер може показати? (Я хочу надати користувачеві випадаючий список зі списком усіх доступних шрифтів і дозволити користувачеві вибрати шрифт.) Я б вважав за краще не заздалегідь твердо кодувати цей список або надсилати його з сервера. (Інтуїтивно здається, що браузер повинен знати, які шрифти у нього є, і це якось повинно бути піддано JavaScript).

Відповіді:


37

Версія JavaScript трохи нестабільна. Він отримує шрифти шляхом ітерації через відомі шрифти та тестування.

Найбільш точним способом (хоча і використання належного плагіна) є використання Flash . Тут ви можете отримати список шрифтів без необхідності тестувати їх окремо, використовуючи розміри.

Вам доведеться вирішити, чи мати точний список за рахунок відсутності роботи на деяких пристроях (iDevices, браузери без плагіна Flash тощо), або частковий список з кращою підтримкою лише за допомогою JavaScript .


30
@Jared За згадку про Flash? Я не сказав, що це єдине рішення, я згадав, що це найточніший спосіб виявлення шрифтів.
alex

4
@alex Так. Це може створити неправильне враження для розробників, особливо нових. Пропоную відредагувати свою відповідь, щоб краще пояснити плюси і мінуси використання Flash, можливо просто "Не рекомендується, але ..." або щось подібне.
Джаред,

19
@Jared Чи потрібно мені писати всі свої відповіді, щоб надати інформацію читачам із нуля, імовірно, що вони новачок у ремеслі? Я пояснив, що Flash вимагає належного плагіна, але я також згадав, що це єдиний спосіб отримати всі доступні шрифти (метод JavaScript просто виявляє підмножину шрифтів, що, мабуть, досить добре для більшості випадків використання). Я також не радий використовувати Flash, але це все, що ми маємо зараз для цього завдання.
alex

7
@Jared Бачите останній абзац? Можливо, ви захочете прочитати його ще раз.
alex

10
@Jared Цей параграф завжди існував.
alex

74

Так є! Я дуже рада, що ви задали це запитання, тому що я зараз хочу також це використати.

+1 за запитання, і ось вам відповідь :)

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

Код з 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;
};

Резюме

Як це працює?

Цей код працює за простим принципом, згідно з яким кожен символ відображається по-різному в різних шрифтах. Тож різні шрифти будуть мати різну ширину та висоту для одного рядка символів однакового розміру шрифту.


2
Дуже хитрий. Це круто.
рекурсивний

4
Дякую, так, це корисно, коли у мене є список шрифтів, щоб перевірити встановлене, але проблема полягає в тому, як створити список назв шрифтів.
mattsh

43
Це дасть лише так / ні для встановлення шрифту.
ректида

2
Спочатку я подумав, що це чудово, але потім знайшов деякі проблеми. Основна проблема полягає в тому, що кожен браузер повертає різні результати. Однозначно не надійний.
Błażej Klisz

11
Цікаво та корисно, але не відповідає на питання. Це не отримує імен шрифтів, доступних у браузері. Даючи неохоче -1.
BenjaminGolder

12

Існує спосіб зробити це за допомогою document.fonts

Повернене значення - це інтерфейс FontFaceSet документа. Інтерфейс FontFaceSet корисний для завантаження нових шрифтів, перевірки стану раніше завантажених шрифтів тощо.

  • Повернуті значення є багатослівними з вагою, стилем тощо.
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;
}
  • Повертає лише сімейство шрифтів
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)];
}

Я протестував його, не пов’язуючи жодного шрифта в HTML, потім зв’язав шрифт Roboto, протестував ще раз, і він додався до результату.


цей фрагмент коду спрацював чудово, дякую! `` listFonts () {let fonts = document ['fonts']; const it = fonts.entries (); нехай arr = []; нехай зроблено = false; while (! done) {const font = it.next (); if (! font.done) {arr.push (font.value [0] .family); } ще {зроблено = font.done; }} // перетворено в set, а потім arr для фільтрації повторюваних значень return [... new Set (arr)]; } `` `
rufreakde

коли я запускаю це у Firefox, воно показує лише веб-шрифти (наприклад, FontAwesome)
Тім Девіс

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
@ Роберт Сколд, так, схоже, це лише IE. Це все ще корисно для багатьох цілей, хоча при серйозному використанні ви повинні мати певну функцію виявлення, щоб люди, які використовують інші браузери, зрозуміли; див., наприклад, cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela

Це не буде працювати в IE11 для Windows Phone ?? чи є ще щось, що мені потрібно додати для Windows Phone ???
jats

4

Рішення FontFaceSet.check ()

  • Виявлення всіх доступних шрифтів є загальноприйнятою технікою відбитків пальців у браузері , тому навряд чи коли-небудь буде додано JS API, який безпосередньо поверне список.
  • Підтримка FontFaceSet.check () є достатньо хорошою для використання, але потребуватиме резервної копії, наприклад ця відповідь для старих браузерів.
  • Перевірка наступного списку шрифтів займає понад 150 мс, тому його потрібно буде запускати лише за необхідності, а результат кешувати.

Список шрифтів 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 / 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()]);
})();


спасибі, це те, що я теж шукаю для можливого веб-дизайну разом із локальними системними шрифтами, щоб отримати значну розбірливість у показі вмісту або синтаксичному аналізі сторінки таким чином, щоб не заповнити багато процесора
Константин,

3

У пошуках цього я також знайшов Font.js , який додає об'єкт Font, подібний до Image, тому можна перевірити, коли шрифт насправді готовий до використання. Також працює над встановленими / системними шрифтами. Недоліком є ​​IE9 + лише через необхідність Object.defineProperty(у інших браузерах він є), але якщо ви використовуєте сучасний Інтернет, це здається ще кращим варіантом. (На жаль, мені доведеться піти з відповіддю вище, проголосованою і рухаючись далі. :))


3

Я додав два методи до детектора Lalit Patel вище:

  • addFont (family, stylesheetUrl, ruleString) -> виявляє, чи існує шрифт 'family', якщо не додає таблицю стилів, завантажуючи шрифт за допомогою стилю таблиціUrl, якщо вказано, або інакше ruleString
  • addFontsArr (arr) -> додає масив шрифтів

За допомогою цього ви можете зробити:

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

код:

/**
 * 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

Можливо, це можна зробити зовсім по-іншому, використовуючи спрайт-лист із відомими зображеннями шрифтів для конкретного символу і порівнюючи його зі знімками елемента полотна, на якому намальований один і той же символ, з тим, що браузер повідомляє як той самий шрифт. Порівняння може бути зроблено з чимось на зразок resemble.js .

Це повільніше, але також повинно дозволити нам виявити, коли браузер бреше.


2

Коротка відповідь. Щодо виявлення шрифтів у браузерах у 2020 році мало що змінилося, за винятком того, що використання Flash зараз ще гірша ідея .

В даний час не існує власної системи браузера, щоб "перерахувати" всі доступні шрифти. Однак браузери дозволять вам перевірити, чи завантажений / готовий шрифт за допомогою API FontFaceSet . Це досить добре підтримується в сучасних браузерах.

Це призначено для показу, якщо веб-шрифт повністю завантажений, АЛЕ він буде працювати і для системних шрифтів. Суть у тому, що вам потрібно надати список шрифтів для перевірки.

Отже, разом із user agent тестом (не завжди точним) ви можете скласти список загальних системних шрифтів для кожного типу пристрою. Потім протестуйте проти тих та будь-яких завантажених веб-шрифтів.

ПРИМІТКА. Це НЕ дасть вам повного списку доступних шрифтів, але ви можете перевірити наявність шрифтів, які зазвичай встановлюються продуктами MS Office або Adobe.


0

Нещодавно я помітив, що якщо я встановлюю значення context.font для полотна HTML5 на щось недійсне, наприклад "сміття", полотно ігнорує. Я не знаю, чи це стосується браузера, але, схоже, це працює в Chrome. Я також бачив інші повідомлення ( шрифт полотна HTML 5 ігнорується ), які вказують, що це трапляється в інших браузерах.

Потім можна було б записати рядок із значенням за замовчуванням, яке, на мою думку, є "10 пікселів без зарубок" ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ), встановити шрифт одному, кого ви тестуєте, і напишіть рядок ще раз. Якщо це те саме, що і перший малюнок, то шрифт недоступний.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.