CSS-live.ru

Исчерпывающее руководство по стратегиям загрузки веб-шрифтов

Перевод статьи A COMPREHENSIVE GUIDE TO FONT LOADING STRATEGIES с сайта zachleat.com, опубликовано на css-live.ru с разрешения автора — Зака Лезермана

Это руководство — не для шрифтовых иконок, у которых свои приоритеты загрузки и применения. К тому же, в долгосрочной перспективе, видимо, лучше сделать ставку на SVG.

Прим. перев.: в названиях методов Зак использует труднопереводимые сокращения FOIT, FOUT и FOFT:

  • FOIT (Flash of Invisible Text) — букв. «мелькание невидимого текста», когда во время загрузки веб-шрифта текст не отображается вообще;
  • FOUT (Flash of Unstyled Text) — букв. «мелькание неоформленного текста», когда во время загрузки веб-шрифта текст отображается шрифтом по умолчанию (напр. системным);
  • FOFT (Flash of Faux Text) — букв. «мелькание синтезированного текста», когда в промежутке между загрузкой основного веб-шрифта и его вариаций (жирный, курсив и т.д.) вместо этих вариаций браузер отображает особым образом измененный основной шрифт (так называемый «ложный жирный» и «ложный курсив», чуть подробнее о них здесь).

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

Перейти к:

A diagram describing the relationship between the font loading strategies

Краткое руководство

Для тех, кто ищет конкретный подход, я подготовил несколько полезных ссылок, ведущих на нужный раздел. Допустим, вам нужен подход, который:

  • отлично проработан, и достаточен в большинстве случаев: FOUT с помощью класса
  • проще всего в реализации: на веб-шрифтах я собаку съел, и летом 2016-го еще не было простых способов, которые браузеры бы поддерживали. Именно с учетом этого я должен признать: если ищете лёгкий способ — попробуйте обойтись без веб-шрифтов. Если не знаете, что делают веб-шрифты, возможно, они просто не для вас. Не поймите неправильно, веб-шрифты великолепны. Но сначала просветите себя о преимуществах (раздел «Значение веб-шрифтов» статьи «В защиту веб-шрифтов» Робина Рэндли послужит хорошим началом. Если знаете другие, поделитесь в комментариях!).
  • нацелен на наилучшую производительность: вам нужен один из подходов критического FOFT. Лично я предпочитаю критическое FOFT с помощью Data URI, но уже смотрю в сторону критического FOFT с предзагрузкой, поскольку поддержка preload браузерами растет.
  • отлично работает с большим объёмом веб-шрифтов: если одержимы веб-шрифтами (всё, что больше 4 – 5 веб-шрифтов или итоговый размер файла более 100кб), то здесь всё хитрее. Для начала постарайтесь сократить количество веб-шрифтов, а если не получается, то придерживайтесь подхода стандартного FOFT или FOUT с двухэтапной отрисовкой. Помогут отдельные подходы FOFT для каждой гарнитуры (группировка обычного, жирного, курсива и так далее).
  • совместим с моим облачным или еще каким-то сервисом хостинга шрифтов: подходы FOFT обычно требуют своего хостинга, поэтому придерживайтесь проверенного и надёжного подхода FOUT с помощью класса

Критерии

  1. Простота реализации: порой просто — это то, что укладывается в срок.
  2. Скорость отрисовки: благодаря FOUT можно немедленно отобразить запасные шрифты и веб-шрифт во время загрузки. Можно предпринять ещё шаги, чтобы сократить время для отображения запасного шрифта и уменьшить влияние FOUT, а то и вовсе устранить его.
  3. Масштабируемость: некоторые подходы загрузки шрифтов поощряют последовательную загрузку веб-шрифтов. А нам нужно, чтобы запросы происходили параллельно. Мы оценим, насколько хорошо работает каждый подход с растущим объёмом веб-шрифтов.
  4. Надежность в перспективе: нужны ли дополнительные исследования и поддержка, если выйдет новый формат шрифта и легко ли его адаптировать?
  5. Поддержка браузерами: хватит ли для работы с огромной базой для удовлетворения требований поддержки браузерами большинства проектов?
  6. Гибкость: насколько легко в этом подходе группировать запросы и перерисовки с перекомпоновками из-за них? Нам нужно контролировать, какие шрифты загружаются и когда.
  7. Надёжность: что случится, если запрос веб-шрифта зависнет? Отобразится ли текст, или из-за одного шрифта развалится весь сайт?
  8. Хостинг: требует ли подход своего хостинга и адаптирован ли он для работы с различными инструментами загрузки шрифтов, предоставленных облачными провайдерами/шрифтоделами шрифта?
  9. Выбор набора символов: некоторые лицензии не позволяют выбирать символы. Некоторые подходы ниже требуют выбирать отдельные символы для оптимальной производительности.

Простой @font-face

Вставьте блок @font-face как есть на страницу и надейтесь на авось. Такой подход по умолчанию рекомендует Google Fonts.

Плюсы

  • Проще некуда: добавляем блок @font-face в CSS с форматами WOFF и WOFF2 (можно даже и формат OpenType, если нужна поддержка Android < 4.4 — сравните WOFF с TTF/OTF на Can I Use)
  • Очень надёжно в перспективе: это поведение веб-шрифта по умолчанию. Использовать шрифты так — это мейнстрим. Чтобы добавить еще формат для шрифтов, нужно всего лишь включить еще один URL в атрибут src вашего правила @font-face со списком форматов через запятую.
  • Хорошая скорость отрисовки в Internet Explorer и Edge: нет FOIT (скрытого или невидимого текста). Полностью поддерживаю это решение ребят из Microsoft.
  • Не требует модификации шрифтов (через выбор набора символов или как-то иначе). Совместимо с лицензиями.

Минусы

  • Плохая скорость отрисовки везде, кроме IE/Edge: до трёх секунд FOIT в большинстве современных браузерах, при дольшей загрузке переключается на FOUT. Хотя запросы могут быть и не такими долгими, но не всегда можно полагаться на надёжность сети: три секунды — слишком долго для невидимого нечитаемого контента.
  • Не такой уж надёжный: у некоторых версий WebKit вообще нет таймаута на FOIT (хотя WebKit совсем недавно исправил это, и Safari 10,  скорее всего, уже включит эти изменения), а значит запросы веб-шрифтов могут стать единой точкой отказа для вашего контента (при зависании запроса контент не отобразится).
  • Нет простого способа группировать запросы или перерисовки вместе. На каждый веб-шрифт придётся отдельный шаг перерисовки/перекомпоновки и свой таймаут для FOIT/FOUT. Это может привести к нежелательным ситуациям вроде «Проблемы с Миттом Ромни из-за веб-шрифта»

Вердикт: не используем.

Font-display

Добавьте новый дескриптор font-display: swap в блок @font-face для переключения на FOUT в браузерах с поддержкой этой функции. Если ваш дизайн не слишком сильно зависит от шрифтов, можно использовать font-display: fallback или font-display: optional. На июль 2016 эта функция не доступна без флага ни в одном браузере.

Плюсы

  • Проще некуда: в блок @font-face добавлен всего лишь один дескриптор CSS.
  • Хорошая скорость отрисовки: в случае поддержки в подавляющем большинстве браузеров мы получили бы FOUT без всякого JavaScript. Подход на чистом CSS стал бы идеальным.
  • Очень надёжно в перспективе: независим от форматов веб-шрифта. При добавлении новых форматов в стек никакие другие изменения не требуются.
  • Очень нажёдный: подход FOUT покажет запасной вариант текста в поддерживаемых браузерах, даже при зависании запроса веб-шрифта. Больше того — веб-шрифты не зависят от JavaScript-полифила — поэтому, если JavaScript не сработает, пользователи всё равно не останутся без веб-шрифта.
  • Не требует модификации шрифтов (через выбор набора символов или как-то иначе). Совместимо с лицензиями.

Минусы

  • Нет стабильной поддержки браузеров. Только в планах разработчиков Chrome, в отличие от Firefox и Edge. Пока поддержка не станет повсеместной, разработчикам, видимо,  без JavaScript здесь не обойтись.
  • Ограниченная гибкость: нет возможности группировать запросы или перерисовки. Это не так уж страшно — если заставить всё мелькать неоформленным текстом, можно избежать «проблемы с Миттом Ромни из-за шрифта», но группировка полезна по другим причинам — об этом позже.
  • Хостинг: нельзя управлять этим свойством на любом известном хостинге веб-шрифта. Его нет в CSS Google Fonts, например. Возможно, с улучшением поддержки браузерами картина изменится.

Вердикт: смело добавляйте уже сейчас, но этого мало

Предзагрузка с preload

Добавьте <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin> для быстрой загрузки шрифта. Смело сочетайте его с простым блоком @font-face, и также не стесняйтесь добавлять свойство font-display в придачу.

Учитывайте: плюсы и минусы этого подхода в значительной степени зависят от выбранной стратегии загрузки шрифта, будь то простой @font-face или font-display.

Плюсы

  • Предельно легко реализовать, один <link> и всё.
  • Скорость отрисовки лучше, чем у блока @font-face. Веб-шрифты запрашиваются на более ранних этапах загрузки страницы.
  • Надёжно в перспективе, если для указания формата шрифта использовать атрибут type. Сегодня всё ещё возможно (хотя маловероятно), что какой-то из браузеров реализует preload раньше WOFF2, к примеру, и отсутствие этого атрибута приведёт к холостому запросу. Так что убедитесь, что он включен.
  • Не требует модификации шрифтов (через выбор набора символов или как-то иначе). Совместимо с лицензиями.

Минусы

  • Масштабируемость: чем больше предзагрузок, тем дольше вы рискуете задержать первоначальное отображение (заметьте, что эти данные были собраны с сайта, который использовал минимально необходимый CSS). Постарайтесь ограничиться одним-двумя самыми важными шрифтами.
  • Ограниченная поддержка браузеров — сейчас только в Blink, но скоро появится и в других.
  • Гибкость: нет возможности группировать отрисовки/перекомпоновки
  • Вряд ли получится использовать это на стороннем хосте. Пришлось бы знать URL нужного веб-шрифта в момент отображения разметки. Google Fonts, к примеру, генерирует их в запросе CSS, сделанном на их CDN.

Вердикт: само по себе не достаточно.

Не использовать веб-шрифты

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

Плюсы

  • Куда уж проще: просто используйте font-family без @font-face
  • Почти мнгновенная скорость отрисовки: не беспокойтесь о FOUT или FOIT.

Минусы

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

Вердикт: в принципе, можно, но я бы не был в восторге от этого.

Встроенный Data URI

Как правило, у этого метода есть два вида встраивания: в блокирующем запросе <link rel="stylesheet"> или в элементе <style> в разметке, генерируемой сервером. И alibaba.com (два шрифта, встроенные в блокирующем CSS-запросе) и medium.com (семь шрифтов) используют этот подход.

Плюсы

  • Отличная с виду скорость отрисовки: при этом подходе нет ни FOUT ни FOIT. Это здорово.
  • Гибкость: не нужно беспокоиться о группировке отрисовок/перекомпоновок — при этом подходе нет ни FOUT ни FOIT.
  • Надёжность: встраивание забрасывает все шрифты в корзину вашего начального запроса к серверу.

Минусы

  • Подвох со скоростью отрисовки: хотя тут и нет FOUT, этот подход может значительно задержать время начального отображения. С другой стороны, текст отобразится «законченным». Но учтите, что даже один шрифт WOFF2 может весить около 10-15кб, и встраивая всего один шрифт, вы рискуете выйти за рамки 14 кб, рекомендуемых для критического CSS в HTTP/1.
  • Браузерная поддержка: нельзя воспользоваться атрибутом src вашего правила @font-face со списком форматов через запятую: этот подход внедряет только один тип формата. На практике это обычно означало WOFF, поэтому приходится выбирать между заведомой поддержкой (WOFF) и гораздо худшей поддержкой браузерами, но с меньшим размером файла (WOFF2).
  • Плохая масштабируемость: запросы происходят не параллельно, а загружаются последовательно.
  • Свой хостинг: конечно, требуется.

Вердикт: используйте этот метод, только если FOUT вас реально бесит. Но я бы не рекомендовал его.

Асинхронная таблица стилей Data URI

Используйте инструмент вроде loadCSS для загрузки таблицы стилей со всеми шрифтами, встроенными как Data URI. Часто это встречается в сочетании с методом localStorage для хранения таблиц в браузере для повторных просмотров.

Плюсы

  • Скорость отрисовки: в основном устраняет FOIT (смотрите замечание в минусах)
  • Гибкость: легко группировать запросы в одной перерисовке (поместите множество Data URI в одну таблицу стилей)
  • Простота: не требует дополнительных изменений CSS. Это большое преимущество. Однако, с реализацией не всё гладко.
  • Надёжность: если асинхронный запрос не сработает, запасной вариант текста всё равно отображается.

Минусы

  • Скорость отрисовки: во время парсинга таблицы стилей и Data URI есть очень заметное, но короткое FOIT. Отвлекает. Я сталкиваюсь с этим методом настолько часто, что узнаю его с закрытыми глазами.
  • Гибкость и масштабируемость: сгруппированные запросы и перерисовки совмещаются друг с другом. При совместной группировке множества Data URI (что приведёт к последовательной, а не параллельной загрузке), они перерисовываются вместе. С этим методом нельзя загружать параллельно и не перерисовывать страницу каждый раз.
  • Сложно поддерживать. Требует собственный метод для определения поддержки форматов шрифта. Вашему JavaScript-загрузчику потребуется определить, какой формат поддерживается (WOFF2 или WOFF) до загрузки таблицы стилей Data URI. Поэтому с выходом нового формата шрифта придётся научиться определять его поддержку в браузере.
  • Поддержка браузерами: можно не возиться с поддержкой шага с загрузчиком и жёстко прописывать WOFF2 или WOFF, но это повлечёт либо излишне тяжелые, либо потенциально холостые запросы (тот же недостаток, что и у встроенных Data URI).
  • Свой хостинг: требуется

Вердикт: хорошо, но можно сделать лучше.

Мелькание неоформленного текста с помощью класса

С помощью API загрузки CSS-шрифтов (и полифила для него) определяйте, когда загрузился тот или иной шрифт, и применяйте его в своем CSS только после успешной загрузки. Обычно это означает переключение класса в элементе <html>. Добавьте по вкусу миксины SASS или LESS, чтобы было проще поддерживать.

Плюсы

  • Скорость отрисовки: устраняет FOIT. Метод испытан и проверен. Это один из подходов, рекомендованный TypeKit.
  • Гибкость: легко группировать запросы в одну перерисовку (используйте один класс для загрузки нескольких шрифтов).
  • Масштабируемость: запросы происходят параллельно.
  • Надёжность: если запрос не сработает, запасной вариант текста всё равно отображается.
  • Хостинг: работает независимо от загрузчика шрифта (легко реализовать для стороннего хоста или существующих блоков @font-face)
  • Отличная поддержка браузерами, полифилл обычно работает везде, где поддерживаются шрифты.
  • Хорошая поддержка в перспективе: полифиллы не зависят от форматов шрифта и должны работать для существующих блоков @font-face. Это означает, что с появлением нового формата можно просто изменить font-face, как обычно.
  • Не требует модификации шрифтов (через выбор набора символов или как-то иначе). Совместимо с лицензиями.

Минусы

  • Надо очень тщательно следить за CSS. Одно-единственное объявление font-family веб-шрифта, не защищенное классом loaded, запросто может вызвать FOIT.
  • Обычно требует жёстко прописывать шрифты, которые нужно загрузить на странице. Это означает риск, что однажды на шрифты уйдет больше трафика, чем нужно для страницы. Помните, что с простым @font-face современные браузеры загрузят только используемые на странице шрифты. Это не требует лишних затрат. Вот почему New York Times живёт себе с сотней разных блоков @font-face на домашней странице — браузер загружает только небольшую их часть. С этим подходом нужно сказать браузеру, какие шрифты загружать, независимо от использования.

Вердикт: это базовый стандарт. Будет работать в большинстве случаев.

Мелькание ложного жирного/ложного курсива, или FOUT с двухэтапной отрисовкой

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

Плюсы

  • Все существующие плюсы подхода FOUT с классом
  • Скорость отрисовки: значительно сокращает скачки контента, происходящих после загрузки шрифта. С учётом двухэтапной загрузки шрифта (обычный шрифт — единственный, берущий на себя наибольшую перекомпоновку), первый этап происходит намного быстрее, чем в случае совместной группировки шрифтов в одну перерисовку.

Минусы

  • Все существующие минусы подхода FOUT с классом.
  • Некоторые дизайнеры не переносят синтез шрифтов. Объективно, синтезированные варианты не так полезны, как их реальные аналоги, но это сравнение нечестно. Учитывая, что синтезированные версии — это только временные заглушки, вопрос нужно ставить так: «Они полезнее, чем резервный шрифт?». Да. Ответ на этот вопрос — да.

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

Критическое FOFT

Единственное различие между этим методом и стандартным подходом FOFT — вместо полного простого шрифта на первом этапе используется подмножество простого шрифта (обычно содержащее только A-Z и необязательные 0-9 и/или знаки препинания). А полный простой шрифт с другими жирностями и стилями загружается на втором этапе.

Плюсы

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

Минусы

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

Вердикт: используйте один из улучшенных вариантов критического FOFT ниже.

Критическое FOFT с помощью Data URI

Этот вариант подхода критического FOFT просто изменяет механизм, с помощью которого изменяет механизм загрузки первого этапа. Вместо того, чтобы начать загрузку, используя обычный АPI загрузки шрифтов в JavaScript шрифтов, мы просто внедрили веб-шрифт как встроенный Data URI прямо в разметку. Как отмечалось ранее, это заблокирует первоначальное отображение, но поскольку мы встраиваем лишь малое подмножество простого шрифта, это ничтожная цена, чтобы в основном устранить FOUT.

Плюсы

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

Минусы

  • Все существующие минусы подхода критического FOFT
  • Небольшой встроенный Data URI незначительно блокирует первоначальное отображение. Это малая цена за сильно уменьшенное FOUT.
  • Свой хостинг: требуется

Вердикт: на сегодня это золотой стандарт, на мой взгляд.

Критическое FOFT с preload

Этот вариант подхода критического FOFT просто изменяет механизм, с помощью которого изменяет механизм загрузки первого этапа. Вместо того, чтобы начать загрузку, используя обычный API JavaScript загрузки шрифтов, мы используем новый стандарт под названием «preload», о котором уже сказано выше. Это должно вызвать загрузку ещё быстрее, чем было возможно раньше.

Плюсы

  • Все существующие плюсы подхода критического FOFT
  • Скорость отрисовки: загрузки должны вызываться на более ранних этапах загрузки страницы, чем у предыдущих методов. Подозреваю, что это ещё разительнее с HTTP-заголовками, но пока не могу подтвердить. Этот метод лучше критического FOFT с помощью Data URI, поскольку использует кэш браузера для повторных запросов, а не запрашивает повторно те же данные веб-шрифта с каждым запросом разметки с сервера.

Минусы

  • Все существующие минусы подхода критического FOFT
  • Используется только с одним форматом шрифта
  • Как указывалось выше, поддержка браузерами ограничена — только Blink на июль 2016.
  • preload может немного задержать первоначальное отображение (заметьте, что эти данные были собраны с сайта, который использовал минимально необходимый CSS).
  • Свой хостинг: вероятно, требуется.

Вердикт: когда поддержка браузерами улучшится, это будет новым золотым стандартом.

P.S. Это тоже может быть интересно:

12 комментариев

  1. «Простой @font-face

    Вердикт: не используем.»

    Поперхнулся, написал этот комментарий и пошёл смотреть мультик про Алладина

    1. Автор же обосновал, чем плох этот способ: риском, что текст вообще никогда не отрисуется в Safari (ниже 10-го), а в других браузерах (кроме IE/Edge) может быть недоступен аж до 3 секунд. Неубедительно?

      1. Судя по описанию, проблема с Safari может возникнуть разве что при использовании EDGE, то есть где-нибудь в Африке. С учётом того, что подавляющее население пользователей EDGE в Африке не имеет денег на Макбуки, эта проблема почти никогда не будет проявляться.

        Неотрисовка текста до 3 секунд — ИМХО ничего страшного тут нет, сайт всё равно грузится какое-то время.

        1. Как раз в Африке проблема старых хилых сетей менее актуальна — туда технологии в принципе пришли поздно, поэтому сразу новые, там скорее всего будет либо ничего, либо уже 3G. Но, во-первых, и 3G для теперешних перегруженных графикой и спецэффектами страниц — не так уж быстро, во-вторых, старые сети еще ох как актуальны за МКАДом и еще подальше (в моем доме вот до сих пор официально нет оптоволокна, только ADSL). Плюс отрисовка страниц, особенно тяжелых, на хилых мобильниках тоже не мгновенная, lenta.ru на моем мобильнике визуально показывалась без текста секунд 10… И это реально злило, должен заметить! :)

          1. Ничего, лет через 9-10 все баги со шрифтами поправят, надо только немножко подождать
            *смотрит в сторону Firefox и border-radius*

  2. Для того, чтоб руководство было исчерпывающим, неплохо бы добавить раздел «суть метода» и желательно размером не меньшим чем толстенькое перечисление всех плюсов и минусов — для тех, кто понимает, как это работает, думаю, они очевидны.

  3. Скрипт из последних нескольких примеров почему-то не срабатывает в IE (11), т.е. имена классов fonts-loaded-1 и fonts-loaded-2 не добавляются.  У кого то также происходит? Как исправить?

    1. Вероятно, дело в том, что IE не понимает промисов:(. Там придется либо подключить для них полифилл, либо переписать по старинке без них, на коллбэках.

  4. Добрый день, на сколько это все актуально сейчас ? Может пришло время когда можно просто использовать font-display: swap  и не заморачиваться со всем этим?

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

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.