Правило @font-face позволяет определить настройки шрифтов, а также загрузить специфичный шрифт на компьютер пользователя.

Внутри конструкции @font-face может находиться набор свойств для изменения параметров шрифта (font-family, font-size, font-style и др.), а также ссылка на шрифтовой файл. Ссылка записывается в виде src: url(URI), где URI - относительный или абсолютный путь к файлу.

body {
    font-family: Arial, Helvetica, sans-serif;
} 

Единственное объявление в приведенном выше правиле - это то, что обычно называют стеком шрифтов. Эта строка определяет шрифт, который браузер должен использовать для указанного элемента (в данном случае для элемента body). Стек - "Arial, Helvetica, sans-serif". Это дает указание браузеру выполнить следующие действия:

  • Найти шрифт под названием "Arial", определенный в CSS, загруженном на страницу, используя @font-face или в операционной системе пользователя. Если этот шрифт найден, использовать его как шрифт для указанного элемента (ов);
  • Если Arial не найден, найти шрифт под названием "Helvetica" в тех же местах. Если он найден, использовать его;
  • Если Helvetica не найден, использовать любой шрифт в качестве шрифта sans-serif по умолчанию в браузере пользователя или операционной системе;

Это довольно упрощенная версия того, что делает браузер. Последнее ключевое слово, используемое в этой строке CSS - это то, что называется общим именем семейства шрифтов. В статье MDN о font-family есть хорошее описание общих имен семейств и почему они используются: "Общие семейства шрифтов являются резервным механизмом, средством сохранения некоторых целей автора таблицы стилей, когда ни один из указанных шрифтов не доступен. Общие имена семейства - это ключевые слова, кавычки для них не нужны. Общее семейство шрифтов должно быть последним элементом в списке имен семейств шрифтов".

Доступные общие имена семейства

Общее семейство шрифтов, согласно спецификации, может быть определено с помощью любого из следующих ключевых слов:

  • serif
  • sans-serif
  • monospace
  • cursive
  • fantasy

Семейство serif хорошо известно, но обратите внимание на то, что спецификация говорит: "Шрифты Serif представляют собой формальный стиль текста для скрипта. Это часто, но не всегда, глифы, которые имеют завершающие штрихи, свисающие или сужающиеся концы или имеют фактические засечные окончания (включая прямоугольные засечки)". Таким образом, здесь стиль шрифта является формальным, без специфических "засечек".

Для шрифтов sans-serif, спецификация говорит: "Символы в шрифтах sans-serif, поскольку термин используется в CSS, обычно имеют низкую контрастность (вертикальные и горизонтальные стержни имеют почти одинаковую толщину) и имеют конечные прямые окончания - без каких-либо свисающих элементов, пересечения центральной линии и других орнаментов". Таким образом, в этом случае ожидается, что шрифт не будет иметь засечек.

Моноширинные шрифты имеют более простое определение: "Единственным критерием моноширинного шрифта является то, что все глифы имеют одинаковую фиксированную ширину".

Хотя эти три семейства довольно распространены, вы, возможно, не слишком знакомы с cursive и fantasy.

Что касается cursive, спецификация говорит: "Символы в cursive шрифтах обычно используют более неформальный стиль скрипта, и результат больше походит на рукописное перо или кисть, чем печатные письма".

Так что хорошо иметь в виду. Если есть конкретное место, где вы используете причудливый рукописный шрифт, ваш стек шрифтов может потенциально включать cursive в качестве конечной записи, если вы считаете, что cursive по умолчанию подходит как достойный резерв.

Точно так же fantasy описывается как: "Прежде всего декоративные или выразительные шрифты, которые содержат декоративные или выразительные представления символов".


Оптимизация шрифтов

Красивый и удобный шрифт - неотъемлемая составляющая хорошего сайта. Благодаря ему нам доступен привлекательный дизайн бренда, более простое чтение текста и удобный интерфейс. Но веб-шрифты дают нам дополнительные возможности! Они позволяют выбрать, найти и увеличить текст в любой момент. Кроме того, надписи не будут зависеть от разрешения экрана и останутся четкими на всех устройствах.

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

- Анатомия шрифта

TL;DR

  • Шрифты Unicode могут содержать тысячи глифов.
  • Существует четыре формата шрифтов: WOFF2, WOFF, EOT и TTF.
  • Для некоторых форматов шрифтов необходимо GZIP-сжатие.

Шрифт состоит из глифов - векторных форм каждой буквы или символа. Поэтому размер файла шрифта зависит от двух переменных: количества глифов в шрифте и сложности их векторных контуров. Например, Open Sans, один из самых популярных веб-шрифтов, содержит 897 глифов, включая латинские, греческие и кириллические символы.

При выборе шрифта обратите внимание на то, какие символы в нем поддерживаются. Если вам нужно перевести контент страницы на разные языки, используйте шрифт, который выглядит одинаково для всех символов. Например, семейство шрифтов Noto от Google разрабатывается, чтобы поддерживать все языки мира. Однако его полный архив весит более 130 МБ!

Конечно, придется поработать над установкой соответствующих настроек, чтобы шрифт не ухудшил работу ресурса. Однако на веб-платформах вы найдете все необходимые инструменты. Далее мы подробно рассмотрим, как совместить красивое оформление и высокую производительность.

- Форматы шрифтов

Сегодня в Интернете используются четыре формата контейнеров шрифтов: EOT, TTF, WOFF и WOFF2. К сожалению, несмотря на возможность выбора, не существует единого формата, который работает во всех браузерах. Например, EOT доступен только в IE, TTF поддерживается в этом браузере только частично. WOFF распространен шире всего, однако его нельзя использовать в некоторых старых браузерах, а над поддержкой WOFF 2.0 работают в настоящее время.

Итак, единого формата для всех браузеров не существует, поэтому мы должны использовать несколько форматов, чтобы страница выглядело одинаково у всех пользователей:

  • Используйте WOFF 2.0 в тех браузерах, которые его поддерживают;
  • Добавьте WOFF для большинства браузеров;
  • Применяйте TTF в устаревших браузерах Android (для версий до 4.4);
  • Добавьте EOT для поддержки устаревших версий IE (до IE9);

Note: Теоретически, существует ещё один формат контейнера шрифтов - SVG. Однако он никогда не поддерживался в IE и Firefox, и сейчас перестает использоваться в Chrome. Из-за ограниченной сферы применения мы специально не рассказываем о нем в этом руководстве.

- Уменьшение размера шрифта с помощью сжатия

Шрифт - это набор глифов, каждый из которых состоит из контуров букв. Конечно, все глифы разные, но, тем не менее, они содержат много похожей информации, которую можно сжать с помощью GZIP или другого совместимого компрессора.

  • Форматы EOT и TTF не сжимаются по умолчанию. Убедитесь, что на ваших серверах настроено сжатие GZIP при передаче ресурсов в этих форматах;
  • К формату WOFF применяется встроенное сжатие. Убедитесь, что компрессор использует оптимальный вариант соответствующих настроек;
  • WOFF2 использует пользовательские алгоритмы предварительной обработки и сжатия для уменьшения размера файла на 30% по сравнению с другими форматами;

Стоит отметить, что некоторые форматы шрифтов содержат дополнительные метаданные, например информацию о хинтинге и кернинге. Они не нужны не для всех платформ, поэтому мы можем сжать файл ещё больше. Узнайте о соответствующих функциях вашего компрессора шрифтов и убедитесь, что у вас есть подходящие ПО для тестирования ресурсов и предоставления их браузерам. Например, Google Fonts поддерживает более 30 оптимизированных вариантов каждого шрифта и автоматически определяет и применяет оптимальный вариант для каждой платформы и браузера.

- Создание семейства шрифтов с помощью @font-face

TL;DR

  • Используйте подсказку format(), чтобы указать форматы шрифтов;
  • Чтобы ускорить работу сайта, разделяйте крупные Unicode-шрифты на поднаборы. Используйте субнастройки Unicode-диапазона и вручную добавьте запасной вариант для более старых браузеров;
  • Чтобы ускорить работу сайта и отрисовку страниц, сократите количество вариантов стиля для каждого шрифта;

С помощью CSS-правила @font-face можно определить расположение определенного шрифта, его свойства стиля и кодовые точки Unicode, для которых он должен использоваться. Используйте сочетание таких объявлений @font-face для создания семейства шрифтов. Браузер будет использовать его, чтобы понять, какие шрифты нужно скачать и применить для текущей страницы. Рассмотрим подробнее, как это работает.

Выбор формата

В каждом объявлении @font-face указано название семейства шрифтов, которое действует как логическая группа из нескольких объявлений, характеристик шрифта, например стиля, толщины и интервала, и дескриптора src, который определяет список расположений шрифта в порядке важности.

@font-face {
	font-family: 'Awesome Font';
	font-style: normal;
	font-weight: 400;
	src:
		local('Awesome Font'),
		url('/fonts/awesome.woff2') format('woff2'), 
		url('/fonts/awesome.woff') format('woff'),
		url('/fonts/awesome.ttf') format('ttf'),
		url('/fonts/awesome.eot') format('eot');
}

@font-face {
	font-family: 'Awesome Font';
	font-style: italic;
	font-weight: 400;
	src:
		local('Awesome Font Italic'),
		url('/fonts/awesome-i.woff2') format('woff2'), 
		url('/fonts/awesome-i.woff') format('woff'),
		url('/fonts/awesome-i.ttf') format('ttf'),
		url('/fonts/awesome-i.eot') format('eot');
}

Обратите внимание, что примеры выше определяют два стиля (обычный и курсив) одного семейства шрифтов Awesome Font, каждый из которых указывает на разный набор ресурсов. В свою очередь, каждый дескриптор src содержит разделенный запятыми список вариантов ресурса в порядке важности:

  • Директива local() позволяет ссылаться на шрифт и загружать его, а также использовать шрифты, установленные на устройстве пользователя;
  • С помощью директивы url() можно загружать внешние шрифты. Она может содержать подсказку format(), указывающую формат шрифта по ссылке;

Note: На устройстве пользователя, особенно мобильном, редко установлены какие-либо шрифты, кроме системных. Поскольку добавить шрифт на телефон или планшет практически невозможно, вы всегда должны предоставлять список внешних расположений ресурса.

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

  • Браузер читает разметку страницы и определяет, какие варианты шрифтов нужны для отрисовки текста;
  • Браузер проверяет, не установлены ли нужные шрифты на устройстве;
  • Если файла нет на устройстве, браузер читает список внешних расположений:
    - Если формат указан, перед скачиванием браузер проверяет, поддерживается ли он. В случае отрицательного ответа программа переходит к следующему варианту;
    - Если указание на формат отсутствует, браузер скачивает ресурс;

С помощью сочетания локальных и внешних директив и подсказки мы можем указать все доступные форматы шрифта. После этого браузер сделает все остальное: определит нужные ресурсы и выберет подходящий формат.

Note: Порядок, в котором указаны варианты шрифтов, имеет значение, потому что браузер выбирает первый поддерживаемый шрифт. Таким образом, если вы хотите, чтобы современные браузеры использовали WOFF2, укажите его до WOFF, и т. д.

- Субнастройки диапазона Unicode

Кроме таких характеристик шрифтов, как стиль, толщина и интервал, правило @font-face позволяет установить набор кодовых точек Unicode, поддерживаемых ресурсом. Благодаря этому мы можем разделить крупный Unicode-шрифт на несколько небольших поднаборов (например, латиницу, кириллицу и греческий алфавит) и скачивать только те глифы, которые нужны для отрисовки текста на конкретной странице.

С помощью дескриптора диапазона Unicode мы можем создать разделенный запятыми список значений диапазона. Каждое из них может быть указано в одной из трех форм:

  • Одна кодовая точка (например, U+416);
  • Диапазон интервала (например, U+400-4ff). Обозначает начальную и конечную кодовые точки диапазона;
  • Диапазон Wildcard (например, U+4??): '?' Символы обозначают любое шестандцатиричное число;

Например, мы можем разделить семейство Awesome Font на латинский и японский поднаборы, которые браузер при необходимости может скачать:

@font-face {
	font-family: 'Awesome Font';
	font-style: normal;
	font-weight: 400;
	src:
		local('Awesome Font'),
		url('/fonts/awesome-l.woff2') format('woff2'), 
		url('/fonts/awesome-l.woff') format('woff'),
		url('/fonts/awesome-l.ttf') format('ttf'),
		url('/fonts/awesome-l.eot') format('eot');
	unicode-range: U+000-5FF; /* Latin glyphs */
}

@font-face {
	font-family: 'Awesome Font';
	font-style: normal;
	font-weight: 400;
	src:
		local('Awesome Font'),
		url('/fonts/awesome-jp.woff2') format('woff2'), 
		url('/fonts/awesome-jp.woff') format('woff'),
		url('/fonts/awesome-jp.ttf') format('ttf'),
		url('/fonts/awesome-jp.eot') format('eot');
	unicode-range: U+3000-9FFF, U+ff??; /* Japanese glyphs */
}

Note: Субнастройки диапазона Unicode особенно важны для азиатских языков, в которых намного больше глифов, чем в западных. Стандартный полный шрифт часто весит мегабайты, а не несколько десятков килобайт.

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

Однако у этого метода есть маленький недостаток: не все браузеры пока поддерживают диапазон Unicode. Одни просто игнорируют соответствующую подсказку и скачивают все варианты, а другие могут вообще не обрабатывать объявление @font-face. Чтобы решить эту проблему, мы должны вручную установить субнастройки в более старых браузерах.

- Оптимизация загрузки и отрисовки

TL;DR

  • Запросы шрифтов отправляются только после создания модели визуализации, поэтому отображение текста может быть задержано;
  • Font Loading API позволяет изменить исходные настройки отложенной загрузки и использовать собственные стратегии загрузки и отображения шрифтов;
  • С помощью встраивания шрифтом можно изменить исходные настройки отложенной загрузки в более старых браузерах;

Полный веб-шрифт со всеми глифами и вариантами стиля, которые могут нам не понадобиться, может весить несколько мегабайт. Чтобы избежать этой проблемы, CSS-правило @font-face позволяет разделить семейство шрифтов на набор ресурсов: поднаборы Unicode, отдельные варианты стиля и т. д.

С помощью объявлений браузер определяет необходимые поднаборы и варианты и скачивает только нужные данные. Это очень удобно, но если мы не будем достаточно внимательны, может произойти ошибка процесса отрисовки. Это замедлит отображение текста и ухудшит работу сайта, чего мы не можем допустить.

- Веб-шрифты и процесс визуализации

  1. Браузер запрашивает HTML-документ;
  2. Браузер анализирует HTML-ответ и создает модель DOM;
  3. Браузер обнаруживает ресурсы CSS, JavaScript и т. д. и отправляет запросы;
  4. После получения CSS-контента браузер создает модель CSSOM и совмещает ее с моделью DOM для получения модели визуализации;
    - После того как модель визуализации определила необходимые варианты шрифтов, отправляются соответствующие запросы;
  5. Браузер отображает макет страницы и ресурсы на нем;
    - Если шрифт ещё не доступен, браузер может не показывать текст;
    - Как только шрифт становится доступен, браузер отображает текст;

Между началом показа контента на странице, которое происходит вскоре после создания модели визуализации, и запросом к шрифту идет "гонка". Из-за этого может возникнуть проблема отсутствия текста. У разных браузеров этот процесс может отличаться:

  • Safari отображает текст только после того, как шрифт скачан;
  • Chrome и Firefox задерживают отрисовку шрифта до 3 секунд, после чего используют запасной вариант. После скачивания ресурса браузеры применяют его для повторной визуализации текста;
  • IE сразу показывает текст с помощью запасного шрифта, а потом заново отображает страницу после скачивания ресурса;

У каждой стратегии визуализации есть свои достоинства и недостатки. Одних повторная отрисовка раздражает, а другие хотят сразу видеть текст и не возражают, если потом его вид изменится. Суть в том, что отложенная загрузка уменьшает количество скачиваемых байтов, но может замедлить отображение текста. Теперь рассмотрим, как улучшить это процесс.

- Оптимизации отрисовки шрифта с помощью Font Loading API

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

var font = new FontFace("Awesome Font", "url(/fonts/awesome.woff2)", {
	style: 'normal', unicodeRange: 'U+000-5FF', weight: '400'
});

font.load(); // don't wait for render tree, initiate immediate fetch!

font.ready().then(function() {
	// apply the font (which may rerender text and cause a page reflow)
	// once the font has finished downloading
	document.fonts.add(font);
	document.body.style.fontFamily = "Awesome Font, serif";

	// OR... by default content is hidden, and rendered once font is available
	var content = document.getElementById("content");
	content.style.visibility = "visible";

	// OR... apply own render strategy here... 
});

Мы можем проверить статус шрифта с помощью директивы check()) и отследить процесс его скачивания. Это позволяет задать собственные правила отрисовки текста на странице:

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

Кроме того, можно совмещать указанные выше стратегии для разного контента на странице: задерживать отображение текста на определенное время или пока шрифт не станет доступным, использовать запасные ресурсы, а затем заново отрисовывать страницу и т. д.

Note: В некоторых браузерах Font Loading API пока находится на стадии разработки. Чтобы вам были доступны его функции, используйте полизаполнение FontLoader или библиотеку webfontloader. Тем не менее, вам придется использовать дополнительные ресурсы - средства поддержки JavaScript.