список всех шрифтов, которые может отображать браузер пользователя

105

Есть ли способ в javascript получить имена всех шрифтов (или семейств шрифтов), которые может отображать браузер? (Я хочу предоставить пользователю раскрывающийся список со списком всех доступных шрифтов и позволить пользователю выбрать шрифт.) Я бы предпочел не жестко кодировать этот список заранее или отправлять его с сервера. (Интуитивно кажется, что браузер должен знать, какие шрифты у него есть, и это как-то должно быть доступно для javascript.)

маттш
источник

Ответы:

37

Версия JavaScript немного нестабильна. Он получает шрифты путем перебора известных шрифтов и тестирования.

Самый точный способ (хотя и с использованием подходящего плагина) - использовать Flash . Здесь вы можете получить список шрифтов, не проверяя их индивидуально, используя размеры.

Вам нужно будет решить, иметь ли точный список за счет того, что он не работает на некоторых устройствах (iDevices, браузеры без плагина Flash и т. Д.), Или частичный список с лучшей поддержкой только через JavaScript .

Алекс
источник
30
@ Джаред За упоминание Флэша? Я не сказал, что это единственное решение, я упомянул, что это наиболее точный способ определения шрифтов.
Alex
4
@alex Да. Это может произвести неправильное впечатление на разработчиков, особенно на новичков. Я предлагаю отредактировать ваш ответ, чтобы лучше объяснить плюсы и минусы использования Flash, возможно, просто «Это не рекомендуется, но ...» или что-то в этом роде.
Джаред
19
@Jared Нужно ли мне писать все свои ответы, чтобы с нуля предоставить читателям информацию, если они впервые в этом деле? Я объяснил, что Flash требует подходящего плагина, но я также упомянул, что в настоящее время это единственный способ получить все доступные шрифты (метод JavaScript просто определяет подмножество шрифтов, что, вероятно, достаточно для большинства случаев использования). Я тоже не в восторге от использования Flash, но это все, что у нас сейчас есть для этой задачи.
Alex
7
@ Джаред Видишь последний абзац? Вы можете прочитать это еще раз.
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
44
Это даст только да / нет для того, установлен ли шрифт.
Ректиде
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 ['шрифты']; const it = fonts.entries (); пусть arr = []; пусть сделано = ложь; пока (! сделано) {const font = it.next (); если (! font.done) {arr.push (font.value [0] .family); } else {done = font.done; }} // преобразовано в set, затем arr для фильтрации повторяющихся значений return [... new Set (arr)]; } `` `
rufreakde
когда я запускаю это в Firefox, он показывает только веб-шрифты (например, FontAwesome)
Тим Дэвис,
6

Решение 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()]);
})();

Крис
источник
спасибо, это то, что я тоже ищу для возможного веб-дизайна с использованием локальных системных шрифтов, чтобы получить большую гибкость при отображении контента или разбора страницы таким образом, чтобы не заполнять много процессора
Константин
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, да, похоже, это только для IE. Он по-прежнему полезен для многих целей, хотя при серьезном использовании у вас должно быть обнаружение некоторых функций, чтобы люди, использующие другие браузеры, могли понять; см., например, cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela
Он не будет работать в IE11 для Windows Phone ?? Что еще мне нужно добавить для Windows Phone ???
jats
4

Я добавил два метода в Детектор Лалит Патель выше:

  • addFont (family, stylesheetUrl, ruleString) -> определяет, существует ли «семейство» шрифта, если нет, добавляет таблицу стилей, загружая шрифт с использованием либо stylesheetUrl, если задано, либо иного 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));
    }
};
кофифус
источник
3

В своем поиске я также нашел Font.js , который добавляет объект Font, очень похожий на Image, поэтому можно проверить, действительно ли шрифт готов к использованию. Также работает с установленными / системными шрифтами. Обратной стороной является IE9 + только из-за необходимости Object.defineProperty(он есть в других браузерах), но если вы работаете в современном Интернете, это кажется еще лучшим вариантом. (К сожалению, мне придется пойти с ответом выше, проголосовать за него и двигаться дальше. :))

Стоффе
источник
3

Короткий ответ. В отношении обнаружения шрифтов в браузерах в 2020 году мало что изменилось, за исключением того, что использование Flash стало еще хуже .

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

Это предназначено для того, чтобы показать, полностью ли загружен веб-шрифт, НО он будет работать и для системных шрифтов. Загвоздка в том, что вам нужно предоставить список шрифтов для проверки.

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

ПРИМЕЧАНИЕ. Это НЕ даст вам полный список доступных шрифтов, но вы можете проверить шрифты, обычно устанавливаемые продуктами MS Office или Adobe.

Брайс Ховитсон
источник
2

Возможно, это можно было бы сделать совершенно другим способом, используя таблицу спрайтов с изображениями известных шрифтов для определенного символа и сравнивая это со снимками элемента холста, на котором тот же символ нарисован с тем же шрифтом, который обозреватель сообщает. Сравнение может быть выполнено с чем-то вроде подобия.js .

Это медленнее, но также должно позволить нам определить, когда браузер лжет.

fzzylogic
источник
0

Недавно я заметил, что если я устанавливаю значение context.font для холста HTML5 на что-то недопустимое, например, «мусор», холст игнорирует это изменение. Я не знаю, зависит ли это от браузера, но похоже, что в Chrome это работает. Я также видел другие сообщения ( шрифт холста HTML 5 игнорируется ), в которых указывается, что это происходит в других браузерах.

Затем можно было бы написать строку со значением по умолчанию, которое, как мне кажется, является «10px sans serif» ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ), установите шрифт к тому, который вы тестируете, и снова напишите строку. Если он такой же, как на первом рисунке, шрифт недоступен.

AFF
источник