FOUT — побочный эффект при использовании @font-face и борьба с ним.

Источник: Fighting the @font-face FOUT.
Автор:  Paul Irish.
Перевод: .

Не вешайте нос! На сегодняшний день ситуация значительно изменилась к лучшему. Ознакомьтесь с более свежей информацией на эту тему.

FOUT (Flash Of Unstyled Text) — так я называю эффект «кратковременного появления не оформленного текста» в Firefox и Opera при наличии правила @font-face.

В июне 2009г. Реми Шарп (Remy Sharp) в прогрессивном порядке задокументировал процесс отображения браузером страницы, в которой использовано at-правило @font-face. Естественно, что браузеры ведут себя по-разному:

Вот, что происходит в Firefox.

В общем-то, текст читаем изначально, однако представлен веб-шрифтом по-умолчанию до тех пор, пока пользовательский шрифт не будет готов к применению.

Следующая иллюстрация демонстрирует последовательность событий, происходящих в Safari при загрузке браузером шрифтов из правила @font-face:

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

Я применил аналогичный тест к Opera 10b и Firefox 3.5b. Оба браузера отображают текст, а после загрузки шрифта сразу же перерисовывают его в новом шрифте. Вот как действует Opera (Есть скриншоты и Firefox, однако в случае с Opera пример получается более наглядным):

Не уверен, но возможно на первом скриншоте имеет место FOUC баг (Flash Of Unstyled Content — Кратковременное проявление не стилизованного контента).

Мнение Реми Шарпа: На мой взгляд реальная проблема заключается в в том, что какое-то время текст отсутствует вовсе. И медленное сетевое соединение на данный момент не является уникальным случаем. Со мной это происходит довольно часто: когда я использую 3G-брелок или подключаюсь к сети через свой iPhone. То есть, чем больше мы сталкиваемся с беспроводными соединениями, тем чаще ощущаем низкую скорость трафика (по крайней мере, последующие несколько лет нам этого не избежать уж это точно). Необходимо понимать, что медленное Интенет-соединение совсем необязательно ассоциируется с людьми, живущими где-то в глуши, это обычное явление, с которым может столкнуться каждый пользователь Сети.

Да, кстати, движку Webkit все-таки следует избавиться от этого бага.

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

Лучшие практические способы обработки шрифтов.

  • Минимизируйте размер шрифтового файла. Этого можно добиться путем использования лишь подмножества шрифта. (*В подмножество включаются только те символы, которые реально задействованы в документе.)
  • Используйте тяжелое кэширование (*'heavy caching' — хранение данных в КЭШе длительный период времени), применяя заголовок с максимально возможным временем жизни (Expires).
  • Gzip-сжатие? Ну, вообще-то, нет. Вам не удастся применить gzip к шрифту. Хотя, с помощью gzip можно сжать CSS файл, содержащий представленные схемой data:uri данные. Однако, много таким образом вы не выиграете — это неверный путь. Стояном Стефановым (Stoyan Stefanov) ,было проведено отличное исследование касательно gzip-сжатия данных из правила @font-face. Если кратко, то результат его тестирования заключается в том, что такой прием может давать 40-45% эффективности. Значит, его стоит использовать.

Когда именно браузеры выполняют загрузку файла шрифта?

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

  • IE выполняет загрузку файла с расширением .eot сразу же после его обнаружения в декларации @font-face.
  • Ни один из браузеров не начинает загрузку шрифтового файла, если он встречает CSS правило, ссылающееся на шрифт, который определен в рамках at-правила @font-face.
  • Движки Gecko, Webkit и браузер Opera не загружают шрифт до тех пор, пока в ходе обработки HTML они не наткнутся на элемент, соответствующий селектору CSS правила, содержащего стек, в состав которого входит шрифт из @font-face правила.

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

В каких ситуациях вы можете увидеть эффект FOUT:

  • Увидите: загрузка и отображение удаленного ttf/ptf/woff файла.
  • Увидите: отображение кэшированного ttf/otf/woff файла.
  • Увидите: загрузка и отображение содержащегося в data:uri ttf/otf/woff файла.
  • Увидите: отображение кэшированного ttf/otf/woff файла, содержащегося в data:uri.
  • Не увидите: отображение шрифта, который установлен заранее и указан в используемом вами шрифтовом стеке.
  • Не увидите: отображение предустановленного, используемого в конструкции local() шрифта.

Первый способ ликвидации FOUT в Firefox: скрываем страницу.

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

Код, отвечающий за реализацию этого подхода, должен находиться в элементе <head>:

function(){
// if firefox 3.5+, hide content till load (or 3 seconds) to prevent FOUT
var d = document, e = d.documentElement, s = d.createElement('style');
if (e.style.MozTransform === ''){ // gecko 1.9.1 inference
s.textContent = 'body{visibility:hidden}';
var r = document.getElementsByTagName('script')[0];
r.parentNode.insertBefore(s, r);
function f(){ s.parentNode && s.parentNode.removeChild(s); }
addEventListener('load',f,false);
setTimeout(f,3000);
}
})();

// Лучим способом усовершенствования этого скрипта будет применение
// правила visibiity:hidden только к тем элементам, в которых
// задействованы веб-шрифты, а не к элементу <body> в целом.
// Хотя вам выбирать, какое правило вписывать в качестве
// значения свойства textContent.

17/11/2011 — Внесено обновление, после которого код вставляется непосредственно в таблицу стилей, устраняет баг FF4.

14/04/2011 — Добавлен нижний комментарий, предлагающий использовать код применительно к целевой секции.

Если используется Firefox, то мы, в первую очередь, определяем его версию (выше 3,5) путем проверки доступности свойства -moz-transform, поддержка которого была добавлена в последующих версиях браузера. Для того, чтобы запрос на доставку шрифта не был отменен, вместо display: none мы используем visibility: hidden, а по окончании загрузки страницы убираем это CSS правило. Выполнение нашего второго действия (делаем целевой объект видимым) привязано к событию load объекта window. Выбор именно этого события связан с тем, что, как было отмечено Стивом Соудерсом (Steve Souders): «загрузка шрифтовых файлов приводит к блокированию генерации события onload в IE и Firefox, хотя ни в Safari, ни в Chrome этого не происходит».

В примере я, к тому же, подстраховываюсь трех секундным интервалом. То есть, если в течение этого периода времени страница не будет полностью загружена, то мы все равно делаем ее видимой. К этому моменту шрифт может еще и не загрузиться, но я полагаю, что такой исход маловероятен. Проблему, которую Реми Шарп обнаружил в случае с сайтом Standards.next, можно считать решенной. Откровенно говоря, я не рекомендую использовать данный прием. Вы можете деактивировать такое поведение, закомментировав строку, содержащую метод setTimeout.

Второй способ ликвидации FOUT в Firefox: скрываем текст.

Об этом я писал в опубликованном на html5rocks.com кратком руководстве по применению веб-шрифтов с помощью правила @font-face.

Сопроводительная в данном случае JavaScript библиотека WebFont Loader предоставляет функционал Google Font API и обеспечивает вас широкими возможностями по контролю над процессом загрузки шрифтов посредством привязки к соответствующим событиям. Теперь давайте обратим внимание на то, как можно имитировать свойственное движку Webkit поведение, заключающееся в скрытии не стилизованного текста на время загрузки определенных правилом @font-face шрифтов, в других браузерах.

<script src="//ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"></script>
<script>
WebFont.load({
custom: {
families: ['Tagesschrift'],
urls : ['http://paulirish.com/tagesschrift.css']
}
});
</script>
/* мы хотим, чтобы все h2 заголовки были оформлены с помощью шрифта Tagesschrift */
.wf-loading h2 {
visibility: hidden;
}
.wf-active h2, .wf-inactive h2 {
visibility: visible;
font-family: ‘Tagesschrift’, ‘Georgia’, serif;
}

В случае, если поддержка JavaScript отключена, текст остается видимым постоянно, а если по какой-либо причине шрифт будет недоступен, то без труда производится «откат» к базовому шрифту serif. В данный момент этот подход следует рассматривать как вынужденную временную меру. Большинство специалистов из области веб-шрифтов предпочитают скрывать базовый шрифт в течении 2-5 секунд и лишь затем показывать его. Эффект от такого тайм-аута наиболее очевиден применительно к мобильным устройствам и в случае со слабыми сетевыми соединениям. По понятным причинам Mozilla ищет пути как можно скорейшего решения этого вопроса.

Использование свойства font-size-adjust является облегченным, но в то же время менее эффективным методом, который на данный момент поддерживается только в Firefox. Такой подход дает вам возможность нормализации высоты используемых в шрифтовом стеке шрифтов до размера x-height требуемого шрифта. Как результат имеем сокращение связанных с FOUT эффектом визуальных изменений. Кстати, сервис встраивания шрифтов Font Squirrel может сообщить вам x-height величину генерируемого шрифта, что дает возможность точно установить значение свойства font-size-adjust.

7/11/2009 — В статью включены разделы о «способах устранения FOUT в Firefox».

8/11/2009 — Доработан код, ликвидирующий FOUT эффект в Firefox, путем включения в него перестраховочного трехсекундного тайм-аута.

14/12/2009 — Добавлен фрагмент «в каких ситуациях вы можете увидеть эффект FOUT».

3/5/2010 — Добавлена информация о способе минимизации FOUT эффекта путем нормализации высоты текста за счет использования значения x-height в свойстве font-size-adjust.

25/5/2010 — Из статьи изъяты потерявшие актуальность данные.

24/8/2010 — Вставлена информация о способе предотвращения FOUT эффекта с помощью WebFont Loader от Google.

14/4/2011 — Вот еще серия экспресс обновлений по FOUT:

  • В Firefox b11 и 4 проблема не стилизованного текста решена! Наконец-то! В результате имеем: текст невидим в течение 3 секунд, и лишь затем он выводится с помощью шрифта по-умолчанию. Остается надеяться на то, что веб-шрифт будет доставлен в отведенный на это период времени.
  • В IE9 включена поддержка форматов WOFF, TTF и OTF, но, ТЕМ НЕ МЕНЕЕ, проблема FOUT в этой версии браузера не решена.
  • У Webkit готов к запуску патч, благодаря которому альтернативный текст выводится после периода в пол секунды. То есть поведение схожее с Firefox, только вместо 3-х имеем 0,5 секунды.

И, кстати, сервисом WebInk представлен небольшой скрипт, известный как "FOUT-B-GONE", который разработан с учетом всех вышеупомянутых фактов. Он поможет избавить посетителей вашего сайта от «удовольствия» созерцания FOUT эффекта в Firefox 3.5 — 3.6 и IE (* Этот метод уже не актуален, и отправлен в веб-архив).

Обзор комментариев

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

«Живучесть» FOUT эффекта объясняется тем, что он практически нечувствителен к изменениям, вносимым в CSS и HTML их новыми версиями. Источник проблемы напрямую связан с приоритетами, заложенными в браузер на программном уровне. Поскольку сразу же после принятия запроса на отображение страницы, пользовательский агент начинает свою работу с того, что получает исходный код страницы и собирает все ее компоненты (требуемые для визуализации вспомогательные ресурсы), то модель объекта документа строится им буквально на лету. Поэтому браузер, руководствуясь исключительно благими целями (поскорее предоставить пользователю контент), может счесть необходимым отобразить в первую очередь текст, обработка которого требует минимум усилий и времени.

Более того, распространению FOUT способствует склонность веб-страниц к избыточному содержанию ссылок на многочисленные таблицы стилей, которые могут быть связаны с необходимостью различного представления документа (печать, мобильные устройства, проекторы, устройства Брайля и т.д.). Отображение страниц может сопровождаться импортом множества CSS файлов, необходимых для оформления рекламных блоков и другого стороннего контента, который диктует собственные условия стилизации. Свойственная таблицам CSS стилей каскадность применения правил заставляет браузеры ждать загрузки всех данных стилей и лишь затем применять их к документу.

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

Несмотря на сложности, связанные с предотвращением появления не стилизованного текста, к 2016 году были разработаны несколько эффективных методов борьбы с подобным поведением браузеров. Однако теперь проблема всплыла в Google Chrome v.50, где при использовании сервиса веб-шрифтов Typekit появляется не только FOUT, но и FOIT эффект (Flash Of Invisible Text — кратковременное проявление невидимого текста). В период загрузки веб-шрифта или его обработки (т.е. неактивности) некоторые браузеры выводят текст с помощью альтернативного системного шрифта, а другие просто скрывают его. Chrome 50 делает и то и другое, по очереди!

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

Прошлым летом эта проблема была решена путем изменения способа доставки Typekit шрифта. Если раньше все начиналось с того, что сначала делался запрос на загрузку скрипта, который в свою очередь вставлял в документ ссылку на соответствующую таблицу стилей, и лишь после ее загрузки и обработки мы получали корректное отображение веб-страницы, то в новом способе отсутствует процесс загрузки CSS файла вообще. Теперь Typekit сценарий вставляет в исходный код документа элемент стиля, содержащий at-правило @font-face, т.е. вместо загрузки отдельной таблицы стилей, браузер сразу занимается доставкой требуемого веб-шрифта. Благодаря такому приему удалось ликвидировать проблему FOUT в Chrome 50.

Использованы следующие публикации:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *