JavaScript библиотеки для работы со шрифтами: полное руководство
Библиотеки шрифтов в JavaScript: обзор инструментов
Как загрузить пользовательский шрифт динамически и гарантировать его готовность перед отрисовкой текста?
Основное решение в современных браузерах - использование встроенного FontFace API. Оно позволяет загружать шрифты из внешних источников и управлять их состоянием без дополнительных библиотек.
// Создание объекта FontFace
const myFont = new FontFace('MyCustomFont', 'url(/fonts/myfont.woff2)');
// Загрузка шрифта
myFont.load().then(function(loadedFace) {
// Добавление в набор доступных шрифтов
document.fonts.add(loadedFace);
console.log('Шрифт загружен и готов к использованию');
}).catch(function(error) {
console.error('Ошибка загрузки шрифта:', error);
});Fonts js (fonts js библиотека)
Пошаговое объяснение: конструктор принимает имя семейства и URL (или массив URL). Метод load() возвращает Promise, который разрешается после полной загрузки. После вызова document.fonts.add() шрифт становится доступным для CSS.
Типичная проблема: ошибка CORS при загрузке шрифта с другого домена. Сервер должен отправлять заголовок Access-Control-Allow-Origin: * (или ваш домен). В противном случае браузер заблокирует загрузку, и Promise завершится с ошибкой.
Решение: настроить серверные заголовки или разместить шрифты на том же домене. Также можно использовать формат woff2, который поддерживается всеми современными браузерами.
Вариант 1: FontFaceObserver - простая обёртка для Promise
Эта библиотека создана для тех случаев, когда нужно отслеживать загрузку шрифтов, объявленных в CSS, без создания объектов FontFace вручную.
// Установка: npm install fontfaceobserver
import FontFaceObserver from 'fontfaceobserver';
const observer = new FontFaceObserver('Open Sans', { weight: 400 });
observer.load(null, 10000).then(function() {
document.documentElement.classList.add('fonts-loaded');
console.log('Open Sans загружен');
}).catch(function() {
console.warn('Open Sans не загрузился за 10 секунд');
});Пояснение: конструктору передаётся имя шрифта (как указано в CSS). Вторым параметром можно передать дескрипторы (weight, style и т.д.). Метод load() принимает текст для проверки (или null) и таймаут в миллисекундах. После загрузки можно добавить класс для отображения, чтобы избежать FOUT (Flash of Unstyled Text).
Проблема: библиотека не управляет самой загрузкой - шрифт должен быть уже подключён через CSS. Если шрифт не указан в CSS заранее, наблюдатель не сработает. Также возможна ошибка, если имя шрифта не соответствует объявленному в CSS.
Решение: точно указывать имя семейства, включая регистр и пробелы. Для проверки можно сначала вывести список загруженных шрифтов через document.fonts.keys().
Вариант 2: Web Font Loader от Google (Typekit) - универсальный загрузчик
Библиотека, позволяющая загружать шрифты из различных источников (Google Fonts, Typekit, самописные). Подходит для проектов, где используются внешние сервисы.
// Подключение через CDN
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.28/webfont.js"></script>
<script>
WebFont.load({
google: {
families: ['Roboto:300,400,700', 'Lato']
},
custom: {
families: ['MyFont'],
urls: ['/css/myfont.css']
},
active: function() {
console.log('Все шрифты загружены');
},
inactive: function() {
console.warn('Не удалось загрузить некоторые шрифты');
}
});
</script>Объяснение: конфигурация содержит разделы для разных провайдеров. Колбэки active и inactive вызываются после завершения загрузки всех шрифтов. Библиотека автоматически добавляет классы в html (например, .wf-active, .wf-inactive), что удобно для стилей.
Проблема: библиотека сама не загружает файлы шрифтов, а полагается на уже подключённые CSS (для Google Fonts - встроенный лист). Если ссылка на CSS неверна, шрифты не загрузятся.
Решение: всегда проверять наличие CSS-файла или правильность API-ключа для Typekit. Для кастомных шрифтов указывать корректный URL на CSS с объявлением @font-face.
Вариант 3: CSS Font Loading API (событие document.fonts.ready)
Если шрифты уже объявлены в CSS через @font-face, можно дождаться их полной загрузки с помощью встроенного события document.fonts.ready.
document.fonts.ready.then(function() {
document.body.classList.add('fonts-ready');
console.log('Все шрифты, объявленные в CSS, загружены');
});
// Альтернатива: проверка конкретного шрифта
document.fonts.load('1em Open Sans').then(function() {
console.log('Open Sans загружен (размер 1em)');
});Пояснение: document.fonts.ready возвращает Promise, который разрешается, когда все шрифты, указанные в CSS, загружены (или отклонены). Метод load() загружает шрифт с заданным размером и возвращает Promise.
Проблема: если какой-то шрифт не загрузится, Promise всё равно разрешится (некоторые браузеры могут выдавать ошибку). Также API не поддерживается в IE11 и старых версиях браузеров.
Решение: использовать полифилл или комбинировать с FontFaceObserver для обратной совместимости.
Расширенные примеры работы со шрифтами через JavaScript
Пример 1: Загрузка нескольких шрифтов с разными начертаниями через FontFace API
async function loadFonts() {
const fontConfigs = [
{ name: 'Roboto', weight: 300, url: '/fonts/Roboto-Light.woff2' },
{ name: 'Roboto', weight: 400, url: '/fonts/Roboto-Regular.woff2' },
{ name: 'Roboto', weight: 700, url: '/fonts/Roboto-Bold.woff2' },
{ name: 'Roboto', style: 'italic', weight: 400, url: '/fonts/Roboto-Italic.woff2' }
];
const fontPromises = fontConfigs.map(config => {
const font = new FontFace(config.name, `url(${config.url})`, {
weight: config.weight,
style: config.style || 'normal'
});
return font.load().then(() => document.fonts.add(font));
});
try {
await Promise.all(fontPromises);
console.log('Все начертания Roboto загружены');
} catch (error) {
console.error('Ошибка загрузки одного из шрифтов:', error);
}
}
loadFonts();Результат: в консоли появится сообщение об успешной загрузке, либо ошибка с указанием проблемного шрифта. После этого можно использовать шрифт в CSS как `font-family: 'Roboto', sans-serif;`.
Пример 2: Динамическое применение шрифта к элементу после загрузки (с использованием FontFaceObserver)
import FontFaceObserver from 'fontfaceobserver';
function applyFontToElement(element, fontFamily, fallback) {
const observer = new FontFaceObserver(fontFamily);
observer.load(null, 5000).then(() => {
element.style.fontFamily = fontFamily;
element.textContent = 'Текст отображается шрифтом ' + fontFamily;
}).catch(() => {
element.style.fontFamily = fallback + ', serif';
element.textContent = 'Шрифт не загрузился. Используется запасной.';
});
}
const header = document.getElementById('dynamic-font-header');
applyFontToElement(header, 'Playfair Display', 'Georgia');Результат: если шрифт Playfair Display загружен за 5 секунд, заголовок отобразится им. Если нет - применится Georgia.
Пример 3: Web Font Loader с кастомными шрифтами и таймаутом
WebFont.load({
custom: {
families: ['MySansFont', 'MySerifFont'],
urls: ['/path/to/mysans.css', '/path/to/myserif.css']
},
timeout: 7000,
active: function() {
document.querySelector('.status').textContent = 'Шрифты загружены';
document.body.style.fontFamily = 'MySansFont, sans-serif';
},
inactive: function() {
document.querySelector('.status').textContent = 'Ошибка загрузки, используем системные';
}
});Результат: на странице появится индикатор статуса. При успехе шрифт применяется, при неудаче - нет.
Пример 4: Отслеживание загрузки каждого шрифта индивидуально через CSS Font Loading API
async function checkFonts() {
const fonts = document.fonts;
for (const fontFace of fonts) {
// fontFace.status может быть 'unloaded', 'loading', 'loaded', 'error'
console.log(`Шрифт ${fontFace.family} (${fontFace.weight}): ${fontFace.status}`);
}
// Дожидаемся конкретного шрифта
try {
await document.fonts.load('bold 16px/1.5 "Open Sans"');
console.log('Open Sans bold загружен');
} catch (e) {
console.warn('Ошибка загрузки Open Sans bold');
}
}
checkFonts();Результат: в консоли последовательно выводится состояние каждого шрифта, а затем сообщение об успехе или ошибке.
Пример 5: Обработка FOUT с помощью запасного шрифта и переключения классов
const fontObserver = new FontFaceObserver('Ubuntu');
// Начальный стиль с запасным шрифтом
const body = document.body;
body.style.fontFamily = 'Arial, sans-serif';
fontObserver.load(null, 3000).then(() => {
// После загрузки переключаем на Ubuntu
body.style.fontFamily = 'Ubuntu, sans-serif';
body.classList.add('custom-font-loaded');
}).catch(() => {
// Оставляем Arial, но добавляем класс-индикатор
body.classList.add('font-load-failed');
});Результат: текст сначала отображается шрифтом Arial, затем после загрузки Ubuntu заменяется. Если загрузка не удалась, остаётся Arial с классом для возможной стилизации.