Don't forget the Chrome Dev Summit, starting Monday at 10:00am (Pacific) and streaming live on YouTube. Schedule.

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

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

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

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

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). ^

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

Шрифт - это набор глифов, каждый из которых состоит из контуров букв. Конечно, все глифы разные, но, тем не менее, они содержат много похожей информации, которую можно сжать с помощью 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: На устройстве пользователя, особенно мобильном, редко установлены какие-либо шрифты, кроме системных. Поскольку добавить шрифт на телефон или планшет практически невозможно, вы всегда должны предоставлять список внешних расположений ресурса.

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

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

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

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

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

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

  • Одна кодовая точка (например, 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 */
}

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

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

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

  1. Как определить нужные поднаборы?
  2. Если субнастройки диапазона Unicode поддерживаются браузером, он автоматически выберет необходимый поднабор. Вам нужно только добавить соответствующие файлы на страницу и указать требуемые диапазоны в правилах @font-face.
  3. Если диапазон Unicode недоступен, следует скрыть все ненужные поднаборы, то есть указать подходящий.
  4. Как создать поднабор шрифта?
  5. Для оптимизации шрифтов и создания поднаборов используйте инструмент pyftsubset с открытым кодом.
  6. Некоторые сервисы шрифтов позволяют вручную установить нужные субнастройки с помощью параметров запроса. Вы сами сможете выбрать требуемый поднабор для вашей страницы. Чтобы получить более подробную информацию, ознакомьтесь с документацией вашего поставщика шрифтов.

Выбор и синтез шрифта

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

Вариант жирности шрифта

Например, на картинке выше показано семейство шрифтов с тремя вариантами жирности для полужирного стиля: 400 (стандартный), 700 (полужирный) и 900 (жирный). Промежуточные варианты, выделенные серым, отображаются в виде ближайшего из указанных значений.

Если для какого-либо значения жирности нет начертания, используется соседний вариант. Обычно высокие значения отображаются в более жирном виде, а низкие - в более тонком.

Алгоритм сопоставления CSS3-шрифтов

Выбор варианта курсива происходит точно так же. Дизайнер шрифта создает разные версии, а мы выбираем, какие из них мы будем использовать. Не указывайте слишком много вариантов, поскольку каждый из них требует отдельного скачивания. Например, мы можем определить два полужирных способа начертания для семейства шрифтов 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: 700;
  src: local('Awesome Font'),
       url('/fonts/awesome-l-700.woff2') format('woff2'), 
       url('/fonts/awesome-l-700.woff') format('woff'),
       url('/fonts/awesome-l-700.ttf') format('ttf'),
       url('/fonts/awesome-l-700.eot') format('eot');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

В примере выше указано семейство шрифтов Awesome Font, состоящее из двух ресурсов. Они содержат одинаковый набор глифов для латиницы (U+000-5FF), но в разных вариантах жирности: стандартном (400) и полужирном (700). Что произойдет, если в CSS-правиле будет указано другое значение жирность или стиль курсив?

  • Если точное совпадение шрифта отсутствует, браузер выберет ближайший доступный вариант.
  • Если на найден версия стиля (например, в примере выше мы не указали версию для варианта для курсива), браузер сам синтезирует начертание.

Синтез шрифтов

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

Стиль шрифта CSS3

В примере выше мы видим разницу между фактическими и синтезированными вариантами для Open-Sans. Все синтезированные варианты созданы на основе одного шрифта со стандартной жирностью (400). Как вы видите, они сильно отличаются. Поскольку информация для создания полужирной версии и курсива не указана, начертание символов будет зависеть от браузера и используемого шрифта.

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

TL;DR

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

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

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

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

У отложенной загрузки шрифтов есть скрытое свойство, которое может замедлить отрисовку текста. Прежде чем определить, как шрифты нужны для показа страницы, браузер должен создать модель визуализации, которая зависит от моделей DOM и CSSOM. Таким образом, запросы для шрифтов будут отправлены позднее, чем для других первоочередных ресурсов. Возможно, браузер не покажет текст до того, как будут скачаны остальные ресурсы.

Процесс визуализации шрифта

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

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

  • 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()) и отследить процесс его скачивания. Это позволяет задать собственные правила отрисовки текста на странице:

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

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

Оптимизация отрисовки шрифта с помощью встраивания

Чтобы решить проблему отсутствия текста, можно использовать другой метод - встроить шрифты в таблицу стилей CSS.

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

Эта техника не очень гибка и не позволяет устанавливать время задержки или стратегии визуализации для разного контента. Однако это простое и надежное решение, которое работает во всех браузерах. Чтобы достичь лучшего результата, поместите все встроенные шрифты в отдельную таблицу стиля и установите для них максимальное значение max-age. Благодаря этому даже если вы обновите CSS, пользователям не придется заново скачивать шрифты.

Повторное использование шрифта с помощью HTTP-кеширования

Обычно шрифты - это статические ресурсы, которые редко обновляются. Убедитесь, что вы указали соответствующий заголовок ETag и оптимальные правила Cache-Control для всех шрифтов.

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

Список методов оптимизации

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

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

  1. Проверяйте использование шрифтов. Не добавляйте слишком много шрифтов и для каждого из них сокращайте число доступных вариантов. Тогда дизайн будет выглядеть однородно, а сайт - быстро реагировать на запросы пользователя.
  2. Разделяйте шрифты на поднаборы. Вы можете разделить ресурс на Unicode-диапазоны, чтобы отправлять только глифы, нужные на определенной страницу. Это уменьшает размер файла и ускоряет его скачивание. Однако при создании поднаборов не забудьте оптимизировать повторное использование шрифтов, чтобы не скачивать одни и те же символы для разных страниц. Мы советуем использовать поднаборы, основанные на видах письменности, например латинице, кириллице и т. д.
  3. Используйте оптимизированные форматы шрифтов для каждого браузера: WOFF2, WOFF, EOT и TTF. Убедитесь, что к форматам EOT и TTF применено сжатие GZIP, так как они не сжимаются по умолчанию.
  4. Укажите правила для кеша и проверки актуальности. Шрифты - это статичные ресурсы, которые редко обновляются. Убедитесь, что сервер отправляет маркер подтверждения и директиву max-age с максимально долгим периодом. Благодаря этому шрифт может использоваться повторно на разных страницах.
  5. Используйте Font Loading API для оптимизации процесса визуализации. Из-за отложенной загрузки отрисовка шрифтов может быть задержана. С помощью Font Loading API можно решить эту проблему для некоторых шрифтов и указать собственные правила отображения и задержки для контента на странице. Для более старых браузеров, которые не поддерживают Font Loading API используйте JavaScript-библиотеку webfontloader или CSS-встраивание.