Убрали Google Fonts – и первая отрисовка ускорилась вдвое. Замеры и грабли

Обсудить
Убрали Google Fonts – и первая отрисовка ускорилась вдвое. Замеры и грабли
Реклама. АО «ТаймВэб». erid: 2W5zFJYNGgy

У нас сайт на SvelteKit с отрисовкой на сервере: тридцать с лишним страниц, немного скриптов, ничего тяжёлого. При этом Lighthouse показывал 74 балла, первая отрисовка – 4,2 секунды, отрисовка основного содержимого – 4,6. Для страницы, где нет ни одной картинки в контенте, это много.

Виноват был один тег.

Что показал разбор

Цепочка критических ресурсов выглядела так:

zvukopis.ru/                                      256 мс   13,3 КБ
  |- fonts.googleapis.com/css2?family=Unbounded…  668 мс    1,5 КБ  <- блокирует отрисовку
       |- fonts.gstatic.com/…/unbounded…woff2    1092 мс   50,9 КБ
       |- fonts.gstatic.com/…/golostext…woff2    1091 мс   22,1 КБ
       |- … всего 8 файлов шрифтов

Аудит render-blocking-resources называл единственный блокирующий ресурс: таблицу стилей Google Fonts. Разбор LCP по фазам: TTFB 610 мс, а задержка отрисовки – 3 993 мс, то есть 87% времени. Грузить было нечего: LCP – это текст, он просто ждал шрифты.

Механика простая и всем известная, но напомню. Браузер получает HTML, видит <link rel="stylesheet"> на чужой домен, останавливает отрисовку, идёт на fonts.googleapis.com: DNS, TCP, TLS – новое соединение к незнакомому хосту. Получает CSS, а в нём ссылки на второй чужой домен, fonts.gstatic.com. Ещё одно соединение. И только потом – сами файлы.

preconnect к обоим доменам у нас стоял, display=swap тоже. Это не помогло: preconnect ускоряет рукопожатие, но не отменяет того, что стилевой файл блокирует отрисовку.

Что сделали

Забрали шрифты к себе. Порядок такой.

1. Взяли те же файлы. Запросили у Google CSS с современным User-Agent и вытащили из него ссылки на woff2 и диапазоны символов. Важная деталь: у переменных шрифтов Google отдаёт один файл на семейство и набор символов, а не по файлу на начертание, – в CSS все веса ссылаются на один и тот же адрес.

2. Оставили нужные наборы символов. Кириллица и латиница обязательны: латиница подтягивается даже на полностью русской странице, потому что в ней живут пробел, цифры и пунктуация. Расширенную латиницу оставили ради одного знака – рубля (U+20BD). Вьетнамский и кириллицу-расширенную выбросили.

3. Положили файлы в исходники, а не в статику. Это ключевой момент для кеша. Файл из static/ отдаётся как есть, с обычными заголовками. Файл, на который есть ссылка из CSS внутри src/проходит через сборщик: он получает хеш в имени и попадает в _app/immutable/а туда сервер уже отдаёт cache-control: public, max-age=31536000, immutableГод кеша без единой строки конфигурации.

4. Объявили предзагрузку. SvelteKit по умолчанию предзагружает только скрипты и стили. Шрифты добавляются хуком:

export function handle({ event, resolve }) {
  return resolve(event, {
    preload: ({ type, path }) =>
      type === 'js' || type === 'css' ||
      (type === 'font' && /\/(unbounded|golos-text)-cyrillic\.[\w-]+\.woff2$/.test(path))
  });
}

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

Тут есть тонкость, которая ловится только в отладчике. При отрисовке на сервере SvelteKit не вставляет <link rel="preload"> в разметку – он отправляет заголовок LinkВ <head> вы ничего не увидите, а в заголовках ответа будет:

link: <./_app/immutable/assets/unbounded-cyrillic.D0U_xfn4.woff2>;
      rel="preload"; as="font"; type="font/woff2"; crossorigin; nopush

Теги в разметку он добавляет только при предварительной отрисовке. Мы сначала решили, что предзагрузка не работает, и полезли искать ошибку в хуке.

Замеры

Lighthouse 12.8.2, мобильный профиль, тот же URL, два прогона.

  Было Стало
Оценка производительности 74 84
Первая отрисовка 4,2 с 2,3 с
Отрисовка основного содержимого 4,6 с 3,9 с
Блокирующие ресурсы таблица стилей Google нет

Первый прогон после изменений дал 48 баллов и 3,4 секунды заблокированного потока – явный выброс на холодном старте. Если меряете у себя, делайте минимум два прогона и берите не первый: разброс лабораторных замеров на одной и той же странице легко достигает двадцати баллов.

Шрифты теперь начинают грузиться на 150-й миллисекунде вместо 684-й – предзагрузка объявлена в заголовке ответа, то есть до разбора HTML.

Чего мы не получили

Вес не уменьшился. Файлы те же самые, те же 213 КБ на восемь наборов символов. Выиграли мы не байты, а соединения и блокировку отрисовки. Если нужен ещё и вес – надо резать глифы, например, оставить в заголовочном шрифте только те символы, которые в заголовках реально встречаются.

LCP всё ещё выше нормы. 3,9 секунды при норме 2,5. Причина уже другая: на первом экране анимации, а элементом LCP браузер выбрал логотип в шапке. Это отдельная история и, честно говоря, отдельная статья.

Лицензии. Шрифты с Google Fonts распространяются по SIL OFL. Класть woff2 к себе можно, но тексты лицензий положите рядом с файлами – это требование, а не вежливость.

Стоит ли оно того

Если у вас на сайте стоит <link> на fonts.googleapis.com – да, почти наверняка. Работы на час: скачать файлы, прописать @font-face с теми же unicode-rangeубрать preconnectобъявить предзагрузку двух начертаний первого экрана.

Плюс к скорости добавляется независимость: у части провайдеров fonts.gstatic.com отвечает нестабильно, и тогда первый экран вашего сайта ждёт чужого таймаута.


Автор делает Звукопись – расшифровку аудио и видео в текст. Сайт, о котором речь, – её витрина.

Изображение на обложке: Flaticon

Hello World! Гайды и обзоры для девелоперов разных мастей.

Комментарии

С помощью соцсетей
У меня нет аккаунта Зарегистрироваться
С помощью соцсетей
У меня уже есть аккаунт Войти
Инструкции по восстановлению пароля высланы на Ваш адрес электронной почты.
Пожалуйста, укажите email вашего аккаунта
Ваш баланс 10 ТК
1 ТК = 1 ₽
О том, как заработать и потратить Таймкарму, читайте в этой статье
Чтобы потратить Таймкарму, зарегистрируйтесь на нашем сайте