[Перевод] Предварительная загрузка шрифтов
Автор статьи, перевод которой мы сегодня публикуем, хочет рассказать о том, почему он выполняет предварительную загрузку шрифтов даже тогда, когда не должен этого делать.
Когда он создавал тот сайт, на котором опубликован оригинал этого материала, он не собирался использовать на нём никаких собственных шрифтов. Это неизбежно повлияло бы на производительность сайта, пусть и не очень сильно. Автор статьи говорит, что он стремился к тому, чтобы сделать быстрый сайт. Однако в итоге решено было использовать один особый шрифт для заголовков страниц и при этом постараться сделать так, чтобы данное решение как можно меньше повлияло бы на производительность проекта.
Начало работы
Для начала я решил сделать файл шрифта как можно меньше. Поэтому я создал подмножество этого шрифта. Другими словами, я отобрал из шрифта только те символы, которые необходимы для слов, находящихся в заголовке.
В результате у меня получился весьма компактный файл, размеры которого составили менее 2 Кб. Кроме того, я поместил его там же, где и все остальные материалы сайта, что позволило избавиться от сторонних зависимостей и от временных затрат, необходимых на подключение к другому домену.
И, наконец, ссылка на файл шрифта была размещена во встроенном в страницу CSS-коде, в верхней части HTML-кода, а не во внешнем CSS-файле.
Это значит, что браузер мог обнаружить и загрузить файл шрифта без необходимости загрузки внешней таблицы стилей. Это, кстати, распространённая причина того, что шрифты загружаются позже, чем нужно.
Неожиданность
Так как особые шрифты необходимы для отображения текста, браузер должен обрабатывать их как высокоприоритетные ресурсы.
В результате я ожидал того, что файл шрифта будет загружен очень быстро. Страницы моего ресурса были, в любом случае, достаточно «лёгкими», поэтому я полагал, что загрузке файла шрифта ничто не должно помешать.
Когда же я проанализировал сайт, я был слегка шокирован.
Итак, взглянув на сайт с помощью инструментов разработчика Chrome и изучив его в Webpagetest, я обнаружил, что высокоприоритетный шрифт загружался после изображений — низкоприоритетных ресурсов.
Изображения загружаются до загрузки шрифта
Мне это показалось полной бессмыслицей.
Я совершенно точно знал о том, что браузер, прежде чем загрузить шрифт, может подождать до тех пор, пока не выяснит, что шрифт нужен для вывода страницы. Но элемент, в котором использовался мой шрифт, находился в самой верхней части страницы, внутри тега
, гораздо выше, чем теги с изображениями, которые загружались до загрузки шрифта. Соответствующий элемент находился выше не только в коде страницы, но и в дереве DOM.
Предварительная загрузка шрифтов как решение проблемы
Атрибут preload
указывает браузеру на то, что ему необходимо заранее загрузить соответствующий ресурс, нужный для вывода текущей страницы.
Использование этого атрибута представляет собой хороший способ ранней загрузки важных ресурсов, которые в противном случае будут обнаружены браузером позже.
Файлы шрифтов — это отличный пример использования данного механизма. Если ссылка на файл шрифта сделана во внешней таблице стилей, то браузер не обнаружит шрифт до тех пор, пока он эту таблицу стилей не загрузит.
Использование атрибута preload
в применении к файлам шрифтов сообщает браузеру о том, что соответствующие шрифты понадобятся ему при выводе страницы.
Кроме того, этот механизм очень легко реализовать с использованием элемента .
В качестве альтернативы можно добавить директиву предварительной загрузки в заголовок ответа (хотя, если не указано иное, некоторые серверы или CDN могут интерпретировать подобную конструкцию как запрос на передачу ресурсов клиенту по инициативе сервера).
Я не ожидал, что на этом сайте мне придётся использовать механизмы предварительной загрузки ресурсов. Мой CSS-код весьма скромен, я встроил его в HTML-код страницы, поступив так для того, чтобы страницы быстрее выводились бы браузерами при первом посещении сайта. Так как мой шрифт не зависел от загрузки внешнего CSS-файла, браузер, в любом случае, должен был бы обнаружить его очень рано и без «подсказок» по поводу предварительной загрузки.
Однако я выяснил, что предварительная загрузка шрифта привела к восстановлению справедливости, к тому, что файл шрифта теперь загружался до загрузки файлов изображений.
Вот водопадная диаграмма из Webpagetest — я выделил те её места, где показана работа с файлом шрифта. В верхней части рисунка предварительная загрузка не используется. В нижней — используется.
Предварительная загрузка и работа с файлом шрифта.
Возможно, полезнее будет рассмотреть раскадровку процесса загрузки страницы (здесь, для наглядности, использовалась имитация очень медленного соединения).
В верхней раскадровке предварительная загрузка не используется. В нижней — используется
Попутно отмечу, что я использовал дескриптор font-display: fallback
. То есть — заголовок изначально выводился с использованием резервного шрифта в том случае, если мой шрифт загружался медленно. Однако для данного теста я эту возможность отключил, так как иначе очень сложно было бы различать этапы загрузки страницы.
Почему это сработало?
Для того чтобы вывести веб-страницу, браузеру нужно построить дерево DOM и дерево CSSOM, которые позже используются для построения дерева рендеринга.
Возникает такое ощущение, что использование для загрузки шрифта элемента с атрибутом
preload
позволяет браузеру приступить к построению CSSOM до завершения создания DOM.
Увидеть это можно на следующих изображениях, на которых показано исследование процесса загрузки страницы с помощью инструментов разработчика Chrome.
Вот как выглядит работа с материалами страницы без использования предварительной загрузки. Сначала создаётся DOM и выполняется загрузка изображений, потом начинается создание CSSOM и выполняется загрузка шрифта.
Работа со страницей без использования предварительной загрузки
А вот — то же самое, но уже с применением предварительной загрузки. Здесь браузер приступает к созданию CSSOM, начинает загрузку шрифта, а потом уже создаёт DOM и начинает загрузку изображений.
Работа со страницей с использованием предварительной загрузки
Есть ли альтернативы предварительной загрузке?
Предположим, я не смог использовать атрибут preload
для повышения приоритета файла шрифта. Как мне можно было бы тогда поступить? Как можно было бы понизить приоритет изображений?
Я, из любопытства, попытался реализовать вышеописанную идею и добавил к элементам, описывающим изображения, атрибут loading="lazy"
. В Chrome 76 (единственный браузер, который на момент написания статьи это поддерживал) это должно было бы понизить приоритет изображений, находящихся за пределами исходной видимой области страницы.
Проверка этой идеи с помощью инструментов разработчика показала, что это приводит к тому, что шрифты загружаются раньше. Возможно, это стоит запомнить, так как уровень поддержки браузерами механизмов ленивой загрузки со временем растёт.
Разные браузеры ведут себя по-разному
Я протестировал проект в нескольких различных браузерах и на нескольких устройствах. В ходе испытаний я выяснил, что iOS Safari (iPhone 8) демонстрирует то же поведение, что и Chrome. А именно, шрифты, по умолчанию, загружаются после изображений, но использование атрибута preload
позволяет исправить ситуацию.
Проблема поздней загрузки шрифтов возникла и в Firefox, но атрибут preload
пока не поддерживается этим браузером по умолчанию, поэтому использование атрибута preload
при просмотре сайта в Firefox ничего не изменило.
В Edge шрифты тоже загружаются позже, чем хотелось бы. Возникло такое ощущение, что в Webpagetest использование атрибута preload
сработало лишь частично. А именно, мне показалось, что это выглядит как двойная загрузка шрифта. Один раз он загружался раньше, второй раз — позже.
Я в предыдущем абзаце говорил о том, что у меня «возникло ощущение», и о том, что мне «показалось». Дело в том, что когда я попытался проверить это поведение с использованием собственной версии Edge, «двойные» загрузки пропали. Теперь у меня возникло такое ощущение, что использование атрибута preload
не приводит к ускорению загрузки шрифтов. Возможно, такая разница в поведении страницы стала следствием исправления некоей ошибки в Edge, хотя если это так — ошибку исправили ценой изменения механизма предварительной загрузки ресурсов.
Итоги
Здесь мы поговорили о том, почему предварительная загрузка шрифтов не помешает даже в том случае, если ссылки на их файлы сделаны во встроенном в страницу CSS-коде.
Браузеры не всегда ведут себя так, как мы того хотим, или так, как мы того от них ожидаем. Но у нас есть инструменты, которые помогают повлиять на поведение браузеров, помогают склонить их в нужную нам сторону.
Раньше я думал, что предварительная загрузка шрифтов на моём сайте совершенно бессмысленна. Из всего того, о чём я рассказал, я извлёк для себя важный урок. Он заключается в том, что никогда не стоит ничего предполагать.
В итоге могу сказать, что предварительная загрузка шрифтов — это отличный способ ускорения вывода текста на веб-страницах.
Уважаемые читатели! Используете ли вы механизмы предварительной загрузки шрифтов в своих веб-проектах?