[Из песочницы] Шрифты в вебе, обзор от 2016 года

b0272b5ccdda4667bd9280ae30f73593.png

Предисловие


Статья — не про всё возможное, связанное с типографикой и текстами, вроде letter-spacing и max-height. Это скорее некоторый список занятных возможностей, которые могут быть углублённо изучены при наличии достаточного любопытства и времени. Надеюсь, для большей части найдётся то, что они не знали или слышали краем уха.

Вступление


В 2016 году нестандартными шрифтами никого не удивишь. 93% браузеров поддерживают их, и около 62% сайтов их используют. Кто-то просто пишет @font-face или вставляет с Google Fonts, кто-то вставляет мегабайт шрифтов в base64 прямо в css. Возможностей много.

Загрузка


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

Общие понятия:

FOIT — flash of invisible text. Сначала отрисовывается страница без текста, затем — сразу с нужным шрифтом.
FOUT — flash of unstyled text. Сначала используется один шрифт, затем — загруженный.
FOFT — некоторые выделяют такой подтип проблем, но встречается реже.

Очень хорошо описаны различные стратегии загрузки шрифтов в недавней статье от Zach Leatherman (русская версия), каждая со своими плюсами и минусами. Я же попробую дать упрощённый обзор различных вариантов: если понадобится изучить, набор ссылок будет под рукой.

@font-face без дополнительных ухищрений
Встречается часто, можно оставить всё как есть на откуп браузеру. Также плюс в том, что пользователи, скорее всего, уже привыкли к такому поведению и не замечают проблем. Минусы: разное поведение в разных браузерах, спорное поведение в некоторых случаях. В сафари и некоторых других браузерах в случае проблем загрузки шрифта может вообще ничего не отображаться длительное время…

Плюсы:

  • Не требует дополнительных усилий
  • Скорее всего, пользователи привыкли к такому поведению и редко заостряют на этом внимание

Минусы:
  • Разное поведение в разных браузерах
  • Спорное поведение в некоторых случаях

Библиотека для определения загрузки шрифта
Общая идея: используем стандартный шрифт до загрузки, после загрузки переключаем класс на body и на всей странице включаются новые шрифты. Это похоже на стандартное поведение Internet Explorer и Edge.

Плюсы:

  • Контроль за использованием шрифтов
  • Небольшой размер библиотек
  • Просто использовать

Минусы:
  • Переключение шрифта заметно пользователю
  • Может приводить к перемещению элементов на странице из-за смены размера текста
  • Требуются дополнительные ухищрения для отсутствия перерисовки шрифта при перезаходе: флаги в куках, sessionStorage

Ссылки:
  • Web Font Loading Patterns (русская версия)
  • FontFaceObserver
  • FontFaceOnload

Кодирование шрифта в base64
Самый разнообразный способ. Можно инлайнить шрифт прямо в основной файл стилей, грузить их асинхронно или вовсе складывать в localStorage. Для кого-то окажется неожиданным то, что после gzip размер отличается от бинарного файла совсем немного.

Плюсы:

  • В общем случае не нужны дополнительные библиотеки для определения загрузки шрифтов
  • При использовании вместе с основной частью css делает ситуации с foit и fout гораздо реже
  • При сохранении в localStorage всё кеширование шрифтов в наших руках

Минусы:
  • Теряется поддержка нескольких типов шрифтов. Либо нужно их дублировать (и тем самым увеличивать общий размер), либо выбрать наиболее распространённый (например, woff и потерять экономию от woff2)
  • Окончание загрузки css — не гарант того, что шрифт может быть сразу отображён! Как и вставка этого css напрямую в страницу. Браузерам требуется время на парсинг шрифтов перед их использованием. Всё это выливается в три стадии отрисовки: дефолтный шрифт, foit, нужный шрифт
  • При вставке просто в css будет задерживать первую отрисовку всей страницы

Ссылки:
  • Описание сохранения шрифтов в localStorage
  • Скрипт загрузки шрифтов с сайта smashingmagazine.com
  • Web Font anti-pattern: data-uris (русская версия)

font-display
Новое css-свойство, которое позволяет контролировать отображение шрифтов во время загрузки. Плюсы-минусы очевидны: простота в использовании и слабая поддержка (скорее, никакая).
Это не совсем способ загрузки, а некоторая оптимизация. С помощью preload можно сократить время до окончания загрузки веб-шрифтов, попутно уменьшить вероятность foit. Браузеры на основе Blink начинают загружать шрифты только после того, как найдут текст на странице с соответствующим шрифтом, а это сильно откладывает окончательный показ страницы: нужно загрузить css, распарсить её, применить к дом-дереву и найти нужный элемент. preload указывает браузеру, что указанный ресурс стоит грузить прямо сейчас. Требуются атрибуты as, type и crossorigin.

Ссылки:

  • Использование preload для шрифтов (русская версия)

Всё остальное
Есть ещё несколько вариаций всего перечисленного, а также вариант через JS (об этом ниже). Например, можно загрузить только одно начертание шрифта, а все остальные использовать при повторных заходах. Или сильно урезать набор используемых символов шрифта (до 5–10 кб) и положить всё это в base64. А может, на первом заходе вообще не использовать на первом заходе нестандартные шрифты, а только загружать их? Также можно не использовать шрифты, если текста почти нет: для логотипов вполне подойдёт SVG. Что выбрать? Каждый решает сам для себя, на основе дизайна, шрифта (-ов) и аудитории.

FontFace


Новое js-api позволяет загружать и использовать шрифты, не используя объявление @font-face вообще. Несколько примеров, чтобы было понятно, о чём речь:
var f = new FontFace("newfont", "url(newfont.woff)", {});
f.load().then(function (loadedFace) {
  document.fonts.add(loadedFace);
  document.body.style.fontFamily = "newfont, serif";
});

fetch('newfont.woff2').then(
  res => res.arrayBuffer()
).then(
  buf => new FontFace("newfont", buf)
).then(ff => {
  document.fonts.add(ff)
});

Троеточие — не часть кода.
  new FontFace('t', 'url( "data:application/font-woff2;base64, <...>")').load();

Проблема в том, что понять, какой формат поддерживается, напрямую нельзя. Поддержка браузерами тоже не полная, но к ней добавится Safari 10. FontFace может быть полезен при отрисовке текста через canvas, так как не придётся создавать невидимые элементы с текстом.

Ссылки:

  • CSS Font Loading Module Level 3
  • Woff2 feature test
  • Пример использования

CSS-свойства


font-weight и font-style
font-weight — достаточно известное свойство. Часто можно увидеть bold, реже — что-то со значением в числах. Стоит отметить то, что веб всё чаще выбирается из bold/italic/bold-italic, сейчас можно увидеть всевозможные thin, light, medium (таких ключевых слов нет, но для них как раз используются числовые значения). Другой интересный вопрос — что делают браузеры, если нужного начертания нет в наличии? В случае жирного/курсивного начертания они пытаются сгенерировать глифы на основе обычной вариации шрифта.

Ссылки:

  • Три способа использования разных начертаний
  • Статья на MDN с примерным описанием алгоритма фолбека
  • Правильное подключение нескольких начертаний одного шрифта
  • Табличка с использованием bolder и lighter
  • Статья на MDN с описанием CSS-свойства font-synthesis

unicode-range
Данное свойство позволяет указать список символов, которые должны быть отображены шрифтом. Это может быть полезно в качестве оптимизации — если на странице не будет символов из этого списка, шрифт не будет загружен вовсе. Также unicode-range можно использовать для стилизации отдельных символов, например, кавычек или для отображения символа рубля. Проблема может быть в поддержке этого свойства браузерами, и хотя она постепенно уходит, всё равно нужно думать: «а что, если бы unicode-range не было».

Ссылки:

  • Статья на MDN с описанием unicode-range
  • Старая статья про стилизацию амперсандов
  • Атака на сайт с помощью инъекции css с unicode-range

font-variant и font-feature-settings
font-variant — несколько обновлённый вариант font-feature-settings. Эти свойства позволяют задействиовать дополнительные возможности, включённые в шрифт. Например, кернинг, диагональные дроби, лигатуры и различные варианты иероглифов.

Ссылки:

  • Описание различных значений font-feature-settings

text-rendering
Свойство задумывалось как обобщённый регулятор скорости отрисовки шрифта, влияя одновременно на кернинг и лигатуры. Несмотря на свою мощность, свойство не получило значительного распространения и заслужило славу бажного и тормозного. В настоящее время имеет смысл воспользоваться font-variant и font-kerning, они дают больше контроля (если не так важна поддержка браузерами, а иначе — font-feature-settings). На самом деле, text-rendering является свойством SVG и не описано ни в одной спецификации CSS.

Ссылки:

  • Описание text-rendering с примерами
  • Описание использования и проблем с text-rendering (русская версия)

font-kerning
font-kerning контролирует работу кернинга (отступы между отдельными сочетаниями букв). Для включения требуется информация о кернинге внутри самого шрифта. Является более современной заменой части функционала font-feature-settings.

Ссылки:

  • Работа с кернингом в браузере, включая таблицы поддержки text-rendering и font-feature-settings (правда. несколько устаревшие)
  • Статья на MDN вместе с интерактивной демкой свойства

font-stretch
Редкоиспользуемое свойство с тяжёлой судьбой. Введённое в CSS 2 и поддержанное в Firefox 9 с Internet Explorer 9, оно было удално из CSS 2.1 и забыто до CSS 3, а не так давно было добавлено в Chrome 48. Оно позволяет использовать альтренативные начертания шрифта, более узкие или широкие.

Использование встроенных шрифтов


В OS X и iOS очень интересная ситуация с системными шрифтами. Недавно там были представлен San Francisco в качестве основного шрифта интерфейса системы. И если Helvitica Neue можно было указать прямо в font-family (хоть порой в сложном варианте), то с San Francisco такой способ был намеренно затруднён. По новой логике, чтобы разработчики не затачивались на какой-то конкретный шрифт, в таких случаях нужно использовать ключевые слова »-apple-system-*», которые поддерживаются с iOS 7. Как аналог, в десктопном хроме недавно добавили значение BlinkMacSystemFont.

В Android есть шрифт Roboto, который недоступен по своему имени. Однако можно использовать простые sans-serif, sans-serif-light, sans-serif-medium и другие.

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

Ссылки:

  • Описание шрифтов -apple-system
  • Использование системных шрифтов в вебе (русская версия)
  • Список названий начертаний Roboto в андроиде, вместе с минимальной версией (ответ про приложения, но в вебе тоже работает)
  • Список названий начертаний Helvetica Neue
  • Список предустановленных шрифтов в Windows
  • Список предустановленных шрифтов в OS X
  • Список предустановленных шрифтов в iOS, watchOS, tvOS

Оптимизация


Самое простое — использовать оптимальный формат. Появившийся не так давно woff2 некоторые оценивают как лучший вариант для шрифтов, из-за примерно 30% уменьшения размера файла по сравнению с woff. Судя по caniuse — woff2 скоро будет поддерживаться в Edge и должен быть в новом Safari 10.

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

Ссылки:

  • FontSquirrel. Сайт, позволяющий конвертировать шрифты, удалять неиспользуемые начертания символов, кодировать в base64 и многое другое
  • FontForge, приложение-редактор шрифтов. Низкоуровневый инструмент — можно удалять отдельные глифы, упрощать кривые, удалять кернинг, вплоть до сдвига отдельных точек
  • Советы по оптимизации от Google
  • fontTools. Библиотека на питоне для манипуляции шрифтами
  • Консольная утилита для конвертации ttf > woff2

Определение текущего шрифта элемента


Иногда стоит задача определения текущего шрифта элемента. В случае разработки могут помочь Chromium Developer Tools и недавно вернувшаяся панелька Fonts из Firefox. В ином случае остаётся только считать размер элемента и сравнивать его после смены значения font-family. Примерно этим занимаются FontFaceOnload и FontFaceObserver, если в браузере недоступен js-интерфейс FontFace. Почему браузеры не предоставляют для этого внятного апи? Дело в том, что отдельные символы внутри одного элемента могут быть отрисованы разными шрифтами, которые перечислен в font-family. На это может влиять упомянутый выше unicode-range и сам набор глифов шрифта.

Где взять нестандартные шрифты?


  • https://fonts.google.com/
  • https://www.fontshop.com/
  • https://www.fontsquirrel.com/
  • Напишите в комментариях свой вариант

Прочее


  • Как растровый шрифт медиум сломал
  • Стоит ли вообще использовать нестандартные шрифты?

Комментарии (2)

  • 15 сентября 2016 в 11:01

    0

    Ни на белке, ни на гугле не нашел аналога всеми любимой Проксимы. Lato вообще кириллический есть только на белке. Gilroy вроде похож, но не совсем то, и бесплатен только в двух начертаниях. Есть какие-то другие варианты?
  • 15 сентября 2016 в 11:21

    0

    На мой взгляд, самый лучший шрифт выглядит так (украдено из twbs@4):
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    

© Habrahabr.ru