Асинхронная загрузка шрифтов Typekit.

Опубликовано: 27 декабря 2016      Перевод:

Источник: Loading Typekit fonts asynchronously.
Автор:  Sean McBride.
Перевод: .

Обновление:Оригинал статьи датирован 25.05.2011 и поэтому на данный момент содержащаяся в ней информация несколько устарела. Сейчас сервис Typekit предоставляет официальную возможность получения встраиваемого кода, который генерируется с помощью Kit Editor. Благодаря чему у вас больше нет необходимости создавать его самостоятельно. Все подробности в этой публикации.

Исходный, так называемый стандартный вариант встраиваемого Typekit кода имеет массу достоинств. Он прост, компактен, очень легок в применении и помогает автоматически избавляться от нежелательного проявления неоформленного текста FOUT (*Flash Of Unstyled Text — «Момент появления не стилизованного текста». Речь идет о том промежутке времени, когда оформленный с помощью веб-шрифтов текст отображается с помощью альтернативного, стандартного системного шрифта, поскольку требуемый для корректного представления файл шрифта еще не загружен. Браузер при этом пытается предоставить пользователю содержимое страницы как можно быстрее в ущерб его визуального оформления). Благодаря именно этим свойствам данный код является отличным выбором для подавляющего большинства сайтов.

Обсуждаемый в настоящей статье шаблон кода асинхронной загрузки представляет собой отличную альтернативу стандартному варианту в ситуациях, когда необходимо исключить вероятность зависимости загрузки оставшегося содержимого страницы от трудностей, связанных с получением Typekit набора. Асинхронные шаблоны более объемные и сложнее в реализации, а также требуют больше настроек, исключающих появление FOUT эффекта. Тем не менее, такой подход гарантирует отсутствие ситуаций, при которых визуализация вашей страницы будет приостановлена в ожидании доставки необходимых ресурсов, если на отрезке между браузером и сетью службы шрифтов что-нибудь пойдет не по плану.

Кстати, в разделе Статус системы Typekit мы используем асинхронный шаблон с привлечением событий загрузки шрифта. Это дает возможность пользователям без труда ознакомиться с информацией о статусе функционирования системы, независимо от возможных перебоев, связанных с доставкой шрифтов или от снижения эффективности работы службы.

Стандартный вариант внедряемого Typekit кода.

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

Если во время синтаксического разбора документа и его визуализации браузер встречает JavaScript тэг, то это блокирует процесс отображения остальных элементов страницы, а производимое дальше выполнение скрипта еще больше замедляет ее обработку. Так происходит потому, что в ходе работы JavaScript сценария веб-браузеры используют одно-потоковую модель. Ведь выполняющийся скрипт может программно изменить исходный код документа с помощью функции document.write() или вообще инициировать редирект на совершенно другую страницу. И поскольку браузер не имеет никакого представления о том, что собирается сделать запущенный скрипт, он ожидает окончания его загрузки и выполнения, и лишь затем продолжает свою работу. Современные пользовательские агенты в ходе выполнения скрипта допускают параллельную доставку других ресурсов страницы, тогда как их старые версии приостанавливают и их.

Стандартная версия встраиваемого Typekit кода состоит всего лишь из пары тегов. Первый инициирует загрузку JavaScript инструментария из нашей сети доставки контента (или CDN). Второй содержит единственную строку встроенного кода, запускающую указанный в предыдущем теге скрипт, который собственно и отвечает за доставку шрифта.

try{Typekit.load();}catch(e){}

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

Как правило, это работает прекрасно, но в тех редких случаях, когда загрузка сценария Typekit занимает слишком много времени, недостаток такого подхода становится очевидным. То, что ранее было желаемой задержкой визуализации, используемой для нейтрализации эффекта FOUT, превращается в серьезную проблему, если время загрузки скрипта превышает несколько секунд. И страница не будет отображена до тех пор, пока запрос на загрузку скрипта остается без ответа. Мы прилагаем все усилия для того, чтобы этого никогда не произошло, работаем с нашими CDN партнерами, добиваясь надежной и своевременной доставки Tipekit инструментариев по всему миру. Но, к сожалению, мы не можем предвидеть каждый случай отключения электроэнергии, появления сетевых сбоев и конфликтов с пользовательскими настройками интернет-обозревателя.

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

Обычный асинхронный шаблон.

Первый вариант кода является наиболее распространенным. Он основан на конструкциях, представленных различными экспертами из области веб-производительности, такими как Стив Соудерс (Steve Souders), которые используются в других встраиваемых JavaScript сценариях, подобных соответствующему коду из Google Analytic.

(function() {
var config = {
kitId: 'abc1def'
};

var d = false;
var tk = document.createElement('script');
tk.src = '//use.typekit.net/' + config.kitId + '.js';
tk.type = 'text/javascript';
tk.async = 'true';
tk.onload = tk.onreadystatechange = function() {
var rs = this.readyState;
if (d || rs && rs != 'complete' && rs != 'loaded') return;
d = true;
try { Typekit.load(config); } catch (e) {}
};
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(tk, s);
})();

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

Как использовать.

  • Расположите этот сниппет в верхней части документа. Это максимально приблизит момент начала загрузки.
  • Измените содержимое выделенного жирным шрифтом конфигурационного объекта, вставив в него ваш собственный Kit ID.
  • В объект конфигурации могут быть добавлены обратные вызовы функций обработки событий процесса загрузки шрифта.

Преимущества.

  • Выполняет загрузку шрифтового инструментария асинхронно, не препятствуя дальнейшей визуализации страницы.

Недостатки.

  • По сравнению со стандартным внедряемым Typekit шаблоном увеличивает объем исходного кода вашей страницы.
  • Во всех браузерах начальный момент загрузки документа может сопровождаться появлением не форматированного текста, который не возможно контролировать или скрывать по причине отсутствия поддержки событий доставки шрифта.

Асинхронный шаблон с обработкой событий шрифта.

Невозможность стандартного асинхронного шаблона скрыть проявление FOUT эффекта в начальные моменты отображения страницы, когда отвечающий за доставку шрифта скрипт загружается и выполняется, связана с отсутствием в нем обработчика событий загрузки шрифта. И это достаточно серьезный недостаток, который может стать причиной нежелательных последствий. В следующем варианте внедряемого Typekit кода, который мы рассмотрим, эта проблема решена. Он создан на основе стандартного шаблона, однако в нем контроль над первоначальным отображением текста в не стилизованном виде достигается посредством отслеживания шрифтовых событий.

(function() {
var config = {
kitId: 'abc1def',
scriptTimeout: 3000
};

var h = document.getElementsByTagName('html')[0];
h.className += ' wf-loading';
var t = setTimeout(function() {
h.className = h.className.replace(/(\s|^)wf-loading(\s|$)/g, ' ');
h.className += ' wf-inactive';
}, config.scriptTimeout);
var d = false;
var tk = document.createElement('script');
tk.src = '//use.typekit.net/' + config.kitId + '.js';
tk.type = 'text/javascript';
tk.async = 'true';
tk.onload = tk.onreadystatechange = function() {
var rs = this.readyState;
if (d || rs && rs != 'complete' && rs != 'loaded') return;
d = true;
clearTimeout(t);
try { Typekit.load(config); } catch (e) {}
};
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(tk, s);
})();

В принципе, основа сценария та же, но в этом варианте присутствует добавочный код, включающий в документ поддержку базового CSS класса шрифтового события в тот период, когда требуемый для отображения шрифта инструментарий еще даже не загружен. При первом выполнении скрипта в html элемент добавляется относящийся к событию загрузки шрифта CSS класс. Далее, если по истечении конфигурируемого таймаута сценарий все еще не получен, класс wf-loading заменяется на wf-inactive. Эти классы могут использоваться вами для скрытия изначально проявляющегося FOUT эффекта путем задания правила visibility: hidden для элементов страницы, в которых используются Typekit шрифты. Форматируемый таким образом текст будет скрыт от пользователя до тех пор, пока к нему будет применен класс wf-loading. Рассмотрим пример:

#page-title {
font-family: proxima-nova-1, proxima-nova-2, sans-serif;
}
.wf-loading #page-title {
visibility: hidden;
}

Как использовать.

  • Расположите содержимое сниппета в начале элемента <head> для того, чтобы загрузка началась как можно быстрее.
  • Измените выделенный жирным шрифтом объект, заменив значения по умолчанию на собственные данные (Kit ID).
  • Укажите необходимый временной интервал в миллисекундах, находящийся в конфигурационном объекте, который определяет задержку между переключением классов wf-loading и wf-inactive в период загрузки скрипта.
  • В объект конфигурации могут быть добавлены обратные вызовы JavaScript функций, привязанные к событиям процесса загрузки шрифта.

Преимущества.

  • Выполняет загрузку инструментария асинхронно, не блокируя процесс отображения остального содержимого страницы.
  • Предоставляет функционал шрифтовых событий, позволяющих контролировать FOUT в ходе загрузки скрипта.

Недостатки.

  • Делает ваш HTML код на несколько байтов больше в сравнении с базовым TypeKit внедряемым кодом, а также со стандартным асинхронным его вариантом.
  • Требует написания дополнительного CSS кода для устранения FOUT эффекта во всех браузерах (в отличие от базового Typekit кода, при использовании которого этот эффект изначально отсутствует, за исключением Firefox).

Другие решения.

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

jQuery аналоги — стандартный и с поддержкой событий загрузки шрифта.

Если в вашем проекте уже задействована jQuery, то вы можете использовать эту библиотеку с целью сокращения объема JavaScript кода, как для базового асинхронного шаблона, так и для его аналога с учетом шрифтовых событий, о которых шла речь выше. Хотя такой подход и позволит вам уменьшить исходный код страницы, но он чреват задержкой получения Typekit скрипта по причине времени, требуемого на загрузку, анализ и выполнение jQury скрипта. Более детально тема асинхронной загрузки Typekit шрифтов с помощью jQuery раскрывается в некоторых GitHub проектах: от yvesvanbroekhoven, от blove и, собственно, typekit.

Встраиваемый код в конце страницы.

Предотвратить начальную задержку визуализации страницы, вызванную применением стандартного Typekit шаблона, можно путем его перемещения из элемента <head> в нижнюю часть элемента <body>. Однако, с другой стороны, позволив таким образом странице беспрепятственно отображаться, мы можем спровоцировать задержку загрузки самого Typekit сценария до тех пор, пока страница практически полностью не будет обработана. К тому же этот подход исключает возможность контроля эффекта не стилизованного текста в начальный период загрузки документа. Более того, в данной ситуации все еще существует вероятность блокировки выполнения другого, находящегося на странице скрипта.

Тег <script> с атрибутом async.

Современные браузеры предоставляют вам возможность использования в скриптовом теге атрибута async, который предписывает браузеру загружать скрипт асинхронно, не блокируя процесс отображения дальнейшего контента страницы. Но, как и следовало ожидать от старых версий IE (c шестой по восьмую), они не поддерживают это свойство, как и атрибут onload. Использование атрибута defer вместо async в ранних версиях IE тоже нельзя назвать хорошей идеей, поскольку такой прием откладывает момент выполнение скрипта до тех пор, пока страница не будет обработана полностью. Если бы не слабая поддержка, то свойство async могло бы кардинально изменить ситуацию и стать полномасштабным решением проблемы асинхронной загрузки. Загляните на GitHub, там вы увидите массу шаблонов асинхронной загрузки с задействованием атрибута async.

На GitHub.

Все рассмотренные в данной статье асинхронные шаблоны доступны на GitHub. Вот парочка отличных проектов на эту тему: Typekit Webfontloader, Typekit FontEvents. Можете посетить этот репозиторий для ознакомления с кодом. Загрузите и проверьте его в действии. В конце концов, вы можете внести свой вклад в его усовершенствование, предложив собственный вариант шаблона асинхронной загрузки JavaScript сценария.