Организация шрифтов в проекте

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

font-family: -apple-system, BlinkMacSystemFont,
            'Segoe UI', Roboto,
            'Helvetica Neue', Helvetica,
             Ubuntu,
             Cantarell,
             Arial, sans-serif,
            'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';

Один из них точно «попадёт» и текст на сайте будет выглядеть привычно для посетителя, как в его операционной системе.

А нестандартные шрифты чаще всего рутина и боль. Я стараюсь организовать свой процесс, рассказываю, как.

Скачать и удобно переименовать

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

Google Fonts позволяет скачивать шрифты со страницы описания и отдаёт *.ttf-вариант. Вверху справа есть кнопка «Download family».

Далее каждую гарнитуру размещаю в папке с названием, соответствующим имени гарнитуры. Внутри папки — файлы с именем по начертанию. Стандартные имена файлов шрифтов с начертаниям сложны и многословны.

├── fonts
│   └── alegreya-sans
│       ├── ...
│       ├── AlegreyaSans-Regular.ttf       # → normal.ttf
│       ├── AlegreyaSans-MediumItalic.ttf  # → 500-italic.ttf
│       ├── AlegreyaSans-Medium.ttf        # → 500.ttf
│       ├── AlegreyaSans-Bold.ttf          # → bold.ttf
│       ├── AlegreyaSans-BlackItalic.ttf   # → 900-italic.ttf
│       ├── AlegreyaSans-Black.ttf         # → 900.ttf

Обычно bold и normal оставляю в буквенном варианте. И в CSS использую также буквенный вариант.

После переименования нужно сконвертировал «тяжёлый» *.ttf в лёгкие *.woff и *.woff2, которые являются архивами.

В редких случаях лучше использовать google-webfonts-helper — там есть все нужные и правильные варианты.

Генерация *.woff/2 из *.ttf-файлов

Раньше я пользовался разными онлайн-инструментами, но увидев консольный способ в докладе Вадима Макеева «_ ___ ______?», стал использовать только его:

# поставить пакет
brew tap bramstein/webfonttools
brew install woff2 sfnt2woff-zopfli

# перейти в папку со шрифтами
cd app/src/fonts/

# сконвертировать ttf
woff2_compress 500.ttf     # → 500.woff2
sfnt2woff-zopfli 500.ttf   # → 500.woff

Увы, инструменты @bramstein/webfonttools для генерации не умеют работать пакетно или по маске типа/имени файла. Каждый *.ttf-файл нужно указать в ручном режиме. Дважды.

Подключение в стилях: SCSS, карты и @each

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

Из имени шрифта получается имя директории со шрифтом — пробелы заменяются на дефисы и регистр меняется на строчные. Всё это происходит в функции slug(string).

$global-font-path : '/fonts/'; // где вообще все шрифты в проекте

// имя шрифтов и их начертания
$fonts: (
  "Alegreya Sans" : ( 300, normal, 500, bold ),
  "Fira Code"     : ( 100, normal, bold )
);

@mixin font-face($font, $weight) {

  // каждый стиль: обычный и курсив
  @each $style in (normal, italic) {

    $path : slug($font);

    // если курсив, то добавить суффикс
    $font-file: if( $style == italic, $weight + '-italic', $weight);

    // повторить этот блок
    @font-face {
      font-family: $font;
      font-display: swap; // это важно для отрисовки
      font-weight: $weight;
      font-style: $style;
      src:
        url('#{$global-font-path}#{$path}/#{$font-file}.woff2') format('woff2'),
        url('#{$global-font-path}#{$path}/#{$font-file}.woff') format('woff');
    }
  }
}

// для каждого шрифта и начертаний..
@each $font, $weight in $fonts {
  // при разном количестве указания начертаний меняется тип переменной в SCSS o_O
  // проверяем это и если > 1, list — проходим по всем в цикле...
  @if type-of($weight) == list {
    @each $weight in $weight {
      @include font-face($font, $weight);
    }
  // если =1, используем это значение
  } @else {
    @include font-face($font, $weight);
  }
}

Разумеется, подключаются только современные форматы. И используется font-display: swap;, чтобы шрифт отображался сразу.

Как только возникает необходимость подключить какой-то шрифт:

  • генерируем *.woff2— и *.woff,
  • добавляем в общую папку шрифтов: ./app/src/fonts/,
  • в переменной $fonts добавляем имя шрифта и необходимые начертания.

Предзагрузка шрифтов

Я предзагружаю файлы базовых начертаний только на главной странице через preload:

<link rel="preload"
      href="/fonts/alegreya-sans/normal.woff2"
      as="font"
      type="font/woff2"
      crossorigin
/>

<link rel="preload"
      href="/fonts/alegreya-sans/bold.woff2"
      as="font"
      type="font/woff2"
      crossorigin
/>

Не забывайте про атрибут crossorigin.


Подробнее о предзагрузке любых ресурсов — в посте Ивана Акулова: «Preload, prefetch and other <link> tags» (английский, или на русском на Хабре).

Выводы, тезисно

  1. Скачивать и конвертировать. Лучше с надёжных источников;
  2. Переименовывать по начертанию, хранить в папке с именем шрифта;
  3. Максимально упросить подключение в стилях. Я использовал SCSS Maps для указания шрифтов/начертаний, @mixin и @each для генерации нужных правил @font-face;
  4. Не забывать про предзагрузку;
  5. Часть работы можно автоматизировать на этапе сборки.

Ещё всякие ссылки про шрифты


Обновлено 22.09.2023: добавлена ссылка на WOFF Has Left the Building.