- PVSM.RU - https://www.pvsm.ru -

До свидания, Google Fonts. Последний аргумент

До свидания, Google Fonts. Последний аргумент - 1

Шрифты Google Fonts страшно популярны. Их загружают более 42,8 миллиона сайтов [1], в том числе Хабр [2]. Библиотека Google Fonts содержит 1023 свободных шрифта и программные интерфейсы для их внедрения через CSS. Очень удобно, казалось бы.

Во многих [3] статьях [4] отмечалось [5], в какую цену [6] обходятся многочисленные запросы через API. Совет самостоятельно хостить шрифты дают много лет. Даже сама Google давала такой совет на конференции Google I/O 2018 года в выступлении на тему веб-производительности [7].

Так почему же многие до сих пор загружают шрифты через Google Fonts API? Ну, был последний аргумент — кэширование. Мол, благодаря общему CDN пользователю не нужно скачивать шрифт заново с каждого сайта. Однако в октябре 2020 года этот аргумент перестал работать. Теперь шрифты Google Fonts больше не кэшируются!

Свой хостинг быстрее

По своей природе Google Fonts даже со всеми оптимизациями не может загружаться клиенту быстрее, чем с родного хостинга [8]. Сравнительные бенчмарки можно посмотреть, например, здесь [4] и здесь [9].

До свидания, Google Fonts. Последний аргумент - 2
Загрузка Google Fonts без preconnect

Оптимизированная загрузка Google Fonts с опцией preconnect (подсказка для браузера заранее подключиться к домену fonts.gstatic.com, чтобы ускорить установку соединения в будущем):

До свидания, Google Fonts. Последний аргумент - 3
Загрузка Google Fonts с preconnect

Дело в том, что Google всегда запрашивает с сервера таблицу стилей:

<link href="https://fonts.googleapis.com/css?family=Muli:400" rel="stylesheet">

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

@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

Но в последнее время Google удалила фунцию local() из @font-face в Google Fonts! То есть шрифты Google Fonts теперь не могут считываться локально, если использовать API.

Из-за дополнительных запросов в к серверу Google возникает лишняя задержка.

До свидания, Google Fonts. Последний аргумент - 4
Загрузка с fonts.gstatic.com с опцией preconnect

До свидания, Google Fonts. Последний аргумент - 5
Загрузка со своего хостинга [8] с опцией preload

Как видим, во втором случае запросы к fonts.gstatic.com отсутствуют, что сразу сокращает время загрузки страницы. Это самый оптимальный вариант.

Размещение шрифтов Google Fonts у себя

Марио Ранфтль [10] создал очень полезный справочник google-webfonts-helper [11]. Здесь можно выбрать конкретные шрифты из библиотеки Google Fonts, нужные наборы символов, начертания, посмотреть поддержку в браузерах — и получить код CSS и непосредственно сами файлы. То есть можно перенести нужные шрифты на свой хостинг [8] в пару нажатий кнопки мыши.

Выбираем шрифт, наборы символов и стили. Чем больше стилей мы выберем, тем больше объём скачивания для клиента.

У разных семейств шрифтов разные уровни проработки. Например, кириллицу поддерживают только 118 из 1023 шрифтов [12] на Google Fonts. Не все шрифты поддерживают полный набор начертаний.

До свидания, Google Fonts. Последний аргумент - 6 [13]
Самое популярное в коллекции Google Fonts семейство шрифтов Roboto

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

/* roboto-regular - latin_cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url('../fonts/roboto-v20-latin_cyrillic-regular.eot'); /* IE9 Compat Modes */
src: local(''),
url('../fonts/roboto-v20-latin_cyrillic-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/roboto-v20-latin_cyrillic-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/roboto-v20-latin_cyrillic-regular.woff') format('woff'), /* Modern Browsers */
url('../fonts/roboto-v20-latin_cyrillic-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/roboto-v20-latin_cyrillic-regular.svg#Roboto') format('svg'); /* Legacy iOS */
}

Вариант для поддержки только современными браузерами:

/* roboto-regular - latin_cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local(''),
url('../fonts/roboto-v20-latin_cyrillic-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/roboto-v20-latin_cyrillic-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

Как видим, здесь функция local() сохранилась, в отличие от официальных стилей Google.

Директория по умолчанию для шрифтов ../fonts/.

Современным браузерам достаточно файлов WOFF и WOFF2, а для устаревших нужны ещё форматы TTF, EOT и SVG. Например, один из вариантов — отказаться от «устаревших» форматов, отдавать только WOFF и WOFF2, а если у клиента старый браузер, то страница отобразится системным шрифтом, без загрузки лишних файлов.

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

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

Просто разместить файлы на своём сервере — недостаточно. Нужно обеспечить, чтобы шрифты загружались заранее, а не после парсинга CSS и создания CSSOM. Это делается через подсказку preload.

<link rel="preload" as="font" type="font/woff2"
href="./fonts/muli-v12-latin-regular.woff2" crossorigin>

<link rel="preload" as="font" type="font/woff2"
href="./fonts/muli-v12-latin-700.woff2" crossorigin>

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

Последний аргумент

Итак, единственным аргументом в пользу Google Fonts была быстрая и надёжная сеть доставки контента (CDN) с кэшированием. Google владеет точками присутствия у всех крупных провайдеров по всему миру.

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

Но теперь так больше не работает. Начиная с версии Chrome 86, которая вышла в октябре 2020 года, межсайтовые ресурсы вроде шрифтов больше не делят общий CDN из-за разделённого браузерного кэша (partitioned browser cache).

В блоге Google [14] объясняется смысл этой функции, которая реализована для защиты от межсайтового трекинга. То есть для приватности. К сожалению, ради этого пришлось пожертвовать производительностью.

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

Долгое время такой механизм хорошо работал с точки зрения производительности. Однако в последнее время появились идеи, как его эксплуатировать во вред людям. Оказалось, что по отклику браузера можно определить, что браузер или 1) скачивает ли ресурс заново, или 2) ресурс уже есть в кэше. Соответственно, в достаточно продвинутой атаке [15] можно понять, какие сайты этот браузер посещал в прошлом. А исследователи доказали, что по истории посещённых сайтов/страниц можно с высокой степенью достоверности идентифицировать личность пользователя, даже если браузер запущен в режиме инкогнито, блокируется JavaScript и удаляются куки. То есть история посещённых страниц — тоже подходящий вариант для фингерпринтинга.

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

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

В новой реализации в качестве ключа кэша используется не только URL ресурса, а новый составной параметр Network Isolation Key. Он состоит из трёх частей: домен верхнего уровня, домен текущего фрейма и URL ресурса.

Таким образом, при посещении нового сайта тот же шрифт будет скачиваться заново с того же URL.

Разделённый кэш присутствует в Safari c 2013 года. Остальные подтянулись только сейчас:

  • Chrome: c версии 86 (октябрь 2020)
  • Safari: с 2013 года
  • Firefox: планируется реализовать [16]
  • Edge: вероятно, в ближайшее время
  • Opera: вероятно, в ближайшее время
  • Brave: вероятно, в ближайшее время
  • Vivaldi: вероятно, в ближайшее время

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

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

Что делать?

Печально, что из-за приватности приходится жертвовать производительностью и делать лишние сетевые запросы.

Что можно сделать пользователю, чтобы не скачивать шрифты каждый раз с каждого сайта?

  1. Отключить загрузку сторонних шрифтов в uBlock Origin.

    До свидания, Google Fonts. Последний аргумент - 7

  2. Отключить загрузку шрифтов в браузере.
    • Firefox: about:config, gfx.downloadable_fonts.enabled;

      До свидания, Google Fonts. Последний аргумент - 8

    • Chrome: запуск с параметром --disable-remote-fonts

  3. В качестве эксперимента попробовать локальный CDN, хотя Decentraleyes [17] и LocalCDN [18] на практике не [19] кэшируют [20] Google Fonts.

Раньше был вариант скачать все шрифты Google Fonts (около 300 МБ) и установить в системе. Но как сказано выше, такой вариант больше не работает из-за изменений @font-face. Если сайт использует Google Fonts, шрифты всё равно будут загружаться каждый раз заново. Локальная установка не поможет.


На правах рекламы

Мощные серверы [21] в аренду на базе новейших процессоров AMD EPYC для размещения веб-проектов любой сложности, от лендингов до крупных новостных порталов или интернет-магазинов. Создайте собственный тарифный план в пару кликов и приступите к работе уже через минуту!

Автор: Mikhail

Источник [22]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/chrome/359802

Ссылки в тексте:

[1] 42,8 миллиона сайтов: https://trends.builtwith.com/websitelist/Google-Font-API

[2] Хабр: https://builtwith.com/habr.com

[3] многих: https://blog.cloudflare.com/fast-google-fonts-with-cloudflare-workers/

[4] статьях: https://medium.com/clio-calliope/making-google-fonts-faster-aadf3c02a36d

[5] отмечалось: https://www.keycdn.com/blog/web-font-performance#disadvantages-of-web-fonts

[6] в какую цену: https://blog.logrocket.com/self-hosted-fonts-vs-google-fonts-api/

[7] выступлении на тему веб-производительности: https://www.youtube.com/watch?v=Mv-l3-tJgGk&feature=youtu.be&t=24m58s

[8] хостинга: https://www.reg.ru/?rlink=reflink-717

[9] здесь: https://habr.com/ru/company/vdsina/blog/490366/

[10] Марио Ранфтль: http://mranftl.com/

[11] google-webfonts-helper: https://google-webfonts-helper.herokuapp.com/fonts

[12] 118 из 1023 шрифтов: https://fonts.google.com/?subset=cyrillic

[13] Image: https://habrastorage.org/webt/wk/sc/w1/wkscw15wtrgultwhyzlmlrf_msm.png

[14] блоге Google: https://wicki.io/posts/2020-11-goodbye-google-fonts/

[15] достаточно продвинутой атаке: http://sirdarckcat.blogspot.com/2019/03/http-cache-cross-site-leaks.html

[16] планируется реализовать: https://bugzilla.mozilla.org/show_bug.cgi?id=1590107

[17] Decentraleyes: https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/

[18] LocalCDN: https://codeberg.org/nobody/LocalCDN/src/branch/main/resources

[19] не: https://codeberg.org/nobody/LocalCDN/issues/159

[20] кэшируют: https://github.com/Synzvato/decentraleyes/issues/34

[21] Мощные серверы: https://vdsina.ru/cloud-servers?partner=habr204

[22] Источник: https://habr.com/ru/post/533208/?utm_source=habrahabr&utm_medium=rss&utm_campaign=533208