Блог “У Василича”

Сабсеттинг шрифтов через glyphhanger

Приблизительное время чтения12 мин.
Фото от Amador Loureiro

Эффективный подход к уменьшению размера файлов шрифтов. Форматирование в woff2 и удаление неиспользуемых глифов через командную строку

Оптимизация шрифтов — обособленный крупный топик, которому посвятили карьеру такие светлые умы как Zach Leatherman и Bram Stein. Можно оптимизировать процесс загрузки шрифтов через CSS Font Loading API и resource hints или улучшать рендер, решая FOUT/FOIT проблему. Но самый базовый способ оптимизации — это уменьшение размера загружаемых ассетов. Он реализуется через 2 основные операции: генерацию веб-форматов и сабсеттинг (уменьшение числа начертаний и использование вариативного шрифта в счёт не беру). Об этих двух операциях и хотелось бы сегодня поговорить.

Предпочтительный формат шрифтов для веба — woff2. У него хорошая браузерная поддержка, так что если вы можете себе это позволить, можно оставить только его (как в этом блоге). Для более широкого покрытия аудитории в качестве фоллбека используется woff, который понимают вообще все. Обычно лицензионные шрифты сразу предоставляют эти форматы, но не редка ситуация, когда всё что у нас есть — это единственный ttf файл. Тогда веб-версии нужно генерировать вручную.

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

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

Поэтому я в итоге пришёл к более грамотному решению — инструменту для командой строки glyphhanger от вышеупомянутого Зака — “Your web font utility belt”, как говорит описание. С ним форматирование и сабсеттинг шрифтов становятся тривиальной задачей. Let’s dive in!

Ставим glyphhanger и смотрим что он умеет

Glyphhanger доступен на npm и ставится на ЭВМ в качестве глобального пакета. Загвоздка здесь в том, что для работы его основных функций требуется установка пакета fonttools, который в свою очередь требует наличие python. Не буду здесь вдаваться в детали установки, за ними обращайтесь к документации. Скажу только, что под Windows у меня были проблемы с развёртыванием среды, отчасти из-за которых я отложил изучение вопроса на год. На MacOS же всё гораздо проще. Так что не будьте как я и разберитесь как поставить его на свою машину — это единственный непростой момент.

Основные возможности glyphhanger:

  1. glyphhanger --subset=*.ttf --formats=woff2,woff — конвертирует шрифт в указанные форматы
  2. glyphhanger --subset=*.ttf --whitelist=U+20-7E — создаёт модифицированные версии шрифта, проводя сабсеттинг на основании переданного вайтлиста
  3. glyphhanger ./test.txt — возвращает список используемых unicode символов для переданных файлов или URL

Без передачи вайтлиста идёт конвертация шрифта в переданные форматы. Так что это всё что нужно для конвертации без сабсеттинга, для которой ранее использовался внешний сервис. Как говорится, enjoy, этот пункт можем закрыть.

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

Определяем вайтлист из unicode символов

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

Первое, что можно сделать — это провести анализ html страницы для получения грубого списка символов:

glyphhanger https://www.p1t1ch.com/blog/how-gatsby-blogs-work/

Команда возвращает список: U+A, U+20-25, U+27-29, U+2B-4A, U+4C-5A, U+5F-7B, U+7D, U+A0, U+410-415, U+417, U+418, U+41A-425, U+427, U+428, U+42D, U+430-44F, U+451, U+2014, U+201C, U+201D, U+2026, U+1F60E

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

Расширяем полученный список до групп

Что ж, приступим. Сначала пойдём по нашему списку в качестве ориентира. В определении групп нам поможет сервис unicode-table.

Группа символов основной латиницы на сайте unicode-table
Основная латиница: 0000 – 007F

U+A, U+20-25, U+27-29, U+2B-4A, U+4C-5A, U+5F-7B, U+7D — основная латиница. Включает буквы английского алфавита, цифры и базовую пунктуацию, короче говоря мастхэв. Всё что до U+20 однако нас не интересует — это спецсимволы вроде переноса строки, не имеющие отношения к типографике, сюда же относится и U+7F. Так что получаем U+20-7E.

Группа символов дополнения к латинице на сайте unicode-table
Дополнение к латинице: 0080 – 00FF

U+A0 — дополнение к латинице. Сам по себе символ — это привычный нам  , идущий отдельно от обычного пробела (U+20). Но в этой группе и помимо него достаточно много полезного. А именно, если брать максимум, то это диапазон U+A0-BF, U+D7, U+F7, включающий набор более редко используемых символов. Ввиду их редкости здесь можно сэкономить на спичках, убрав те из них, которые точно не будут использоваться — это уже делается персонально. Для себя остановился на выборке U+A0, U+A2, U+A3, U+A7, U+A9, U+AB, U+B0, U+B1, U+BB, U+D7, U+F7 (¢£§©«°±»×÷). Эта та группа, где имеет смысл обратиться к списку глифов используемого шрифта, изучив какие символы он определяет.

Если в вайтлист передать unicode символы, которые не определены шрифтом, то не произойдёт ничего криминального. Так что можно спокойно указывать диапазоны по общей unicode таблице.

Группа символов кириллицы на сайте unicode-table
Кириллица: 0400 – 04FF

U+410-415, U+417, U+418, U+41A-425, U+427, U+428, U+42D, U+430-44F — кириллица. Это довольно широкая группа символов, из которой нас интересует только русский алфавит — это U+410-44F. Но те из вас, кто хоть раз писал регулярные выражения, покрывающие русский алфавит, знают, что буква “Ё” здесь с подвохом — она стоит обособленно от основного диапазона, а именно U+401 и U+451 для прописной и строчной соответственно. В итоге получаем U+401, U+410-44F, U+451 — ещё один мастхэв для кириллического сайта.

Группа символов основной пунктуации на сайте unicode-table
Основная пунктуация: 2000 – 206F

U+2014, U+201C, U+201D, U+2026 — основная пунктуация. В этой группе нас интересуют вариации тире и кавычек и многоточие, что при расширении превращается в U+2013, U+2014, U+2018, U+2019, U+201C, U+201D, U+2026. Все символы этой группы относятся к “умной” пунктуации. Обычно в исходниках мы используем знак минуса вместо тире, обычные кавычки вместо типографических и три отдельные точки вместо символа многоточия. Такие инструменты как SmartyPants программно конвертируют текст в более презентабельную версию, и для поддержки итоговых символов и нужен этот диапазон.

U+1F60E — эмоджи. Они обычно не обрабатываются шрифтом кроме ряда исключительных случаев, так что пропускаем.

Добавляем пропущенные символы

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

Группа символов валют на сайте unicode-table
Символы валют: 20A0 – 20CF

U+20A0-U+20CF — символы валют. Будет достаточно U+20AC, U+20BD — евро и рубль соответственно.

Группа буквоподобных символов на сайте unicode-table
Буквоподобные символы: 2100 – 214F

U+2100-U+214F — буквоподобные символы. Здесь выбор зависит напрямую от возможностей шрифта, например для моего реализованы только 5 символов, из которых я возьму U+2116, U+2122 — знаки номера (№) и торговой марки (™).

Группа символов математических операторов на сайте unicode-table
Математические операторы: 2200 – 22FF

U+2200-U+22FF — математические операторы. Целая куча их! Будь у меня математический блог, я бы здесь разгулялся, но в простейшем случае будет достаточно выборки U+2248, U+2260, U+2264, U+2265 (≈≠≤≥).

Ну и всё. Остальное уже — это добавление экзотики. Нужно рассматривать конкретный шрифт, отобрав среди его глифов те, которые не были покрыты.

Финальный вайтлист выглядит следующим образом: U+20-7E, U+401, U+410-44F, U+451, U+A0, U+A2, U+A3, U+A7, U+A9, U+AB, U+B0, U+B1, U+BB, U+D7, U+F7, U+2013, U+2014, U+2018, U+2019, U+201C, U+201D, U+2026, U+20AC, U+20BD, U+2116, U+2122, U+2248, U+2260, U+2264, U+2265

Пробуем glyphhanger в деле и измеряем профит

Разберу этот процесс на примере шрифта Commissioner, который используется на этом сайте. Это опенсоурсный вариативный шрифт с OFL лицензией, которая позволяет его модификацию. Commissioner представлен только в ttf формате, так что в любом случае веб-версии придётся генерировать самим. Вариативный шрифт включает в себя все начертания, в том числе italic через SLNT ось, так что это один файл шрифта на весь сайт.

Для просмотра списка глифов нам поможет Wakamai Fondue (what my font can do, get it?). Исходный шрифт включает 1124 глифа и имеет конский размер в 723KB.

Характеристики оригинального файла шрифта Commissioner на сайте Wakamai Fondue
Оригинальный Comissioner включает 1124 глифа

Теперь для получения из ttf файла модифицированной версии шрифта в woff2 и woff форматах запустим следующую команду в директории со шрифтом:

glyphhanger --subset=*.ttf --formats=woff2,woff --whitelist=U+20-7E,U+401,U+410-44F,U+451,U+A0,U+A2,U+A3,U+A7,U+A9,U+AB,U+B0,U+B1,U+BB,U+D7,U+F7,U+2013,U+2014,U+2018,U+2019,U+201C,U+201D,U+2026,U+20AC,U+20BD,U+2116,U+2122,U+2248,U+2260,U+2264,U+2265

Скриншот успешного выполнения команды в интерфейсе консоли
Сабсеттинг прошёл успешно

После успешной конвертации проверим характеристики. Получаем 291 глиф весом в 112KB.

Характеристики модифицированного файла шрифта Commissioner на сайте Wakamai Fondue
Модифицированный Comissioner ужался до 291 глифа

Сравниваем профит

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

723KB — оригинальная версия вариативного шрифта в ttf формате. Прямо так на сайты его никто не грузит (хотя кого я обманываю).

332KB — woff версия без сабсеттинга. Если нужно поддерживать старые браузеры, то используется для них. Ну или если разработчик не знает про woff2.

257KB — woff2 версия без сабсеттинга. Такой будет основной файл, если не заморачиваться. В принципе неплохо, вариативный шрифт тащит. Для сравнения woff2 версия статичного начертания для этого шрифта весит в среднем 60KB, так что размер сравним с 4 начертаниями, вот только их здесь гораздо больше.

Альтернативно Commissioner представлен через 54(!) статичных начертания, чтобы поддерживать основные значения 4 осей.

136KB — woff версия с сабсеттингом. Выигрыш в 2.5 раза по сравнению с обычной woff версией.

112KB — woff2 версия с сабсеттингом, “царь во дворца”. Выигрыш более чем в 2 раза по сравнению с обычной woff2 версией и почти в 6.5 раз в сравнении с оригиналом. Чтобы вы понимали, это вся типографика сайта, с начертаниями от 100 до 900, поддержкой italic и fancy загогулинами, которые можно видеть в заголовках. Я видел отдельные статичные woff2 начертания, которые весили больше, так что это очень хороший результат.


Подытоживая, glyphhanger — ваш путь к успеху при загрузке шрифтов на сайт. С ним не нужно уповать на работоспособность внешних сервисов, к тому же конвертация шрифтов через командную строку ощущается более по-хакерски. Если лицензия позволяет, то через него можно проводить сабсеттинг, который даже при щадящей выборке символов, даёт выигрыш более чем в 2 раза по сравнению с обычной версией woff2. Можете использовать сниппет из этого поста для быстрого решения или доработать его под свой шрифт.

p1t1ch.com