Frontender Magazine

Решение проблем c @font-face в медиазапросах

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

Соединение с интернетом на мобильных устройствах по качеству часто уступает соединению на настольных компьютерах, следовательно загрузка подключённых шрифтов может затянуться на несколько секунд. Предотвратить это можно используя правило @font-face только для ряда устройств c определенным размером экрана используя медиазапросы. К сожалению, такой подход не работает в некоторых браузерах, включая все версии Internet Explorer и Firefox старше 10 версии. В этой статье вы найдете решение проблемы, которое позволяет достичь баланса между использованием хаков и производительностью.

В чём суть проблемы?

Начав работу над новым сайтом, я хотел чтобы он был хорошо оптимизирован под мобильные устройства без ущерба для производительности. Одна из главных проблем, которых мне хотелось избежать — это явление, которое часто можно встретить просматривая веб-сайты на смартфоне: блок пустого пространства там, где должен быть контент. Причина этого — применение подключённого шрифта к тексту, который не загрузился полностью. Это явление продемонстрировано на изображении ниже.

скриншот

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

@font-face в медиазапросе

Для простоты, создадим два файла: index.html и style.css. Первый — это образец страницы с текстом, к которому применён подключённый шрифт, второй содержит стили для этой страницы.

Наша гипотетическая страница index.html может выглядеть так:

<!DOCTYPE html>
<html>
   <head>
      <link rel="stylesheet" href="style.css" />
   </head>
   <body>
      <p>
         Это безумно красивый текст, оформленный подключённым шрифтом.
      </p>
   </body>
</html>

Как видите, это очень простая страница с одним текстовым абзацем и ссылкой на таблицу стилей.

Дальше вы видите код нашего гипотетического файла style.css, для которого использован подход «сначала мобильные»:

p {
   font-family: Arial,Helvetica,sans-serif;
}

@media only screen and (min-width: 980px) {
   @font-face {
      font-family: "OctinSports";
      src: url("fonts/octinsports.eot");
      src: url("fonts/octinsports.eot?#iefix") format("embedded-opentype"),
      url("fonts/octinsports.woff") format("woff"),
      url("fonts/octinsports.ttf") format("truetype"),
      url("fonts/octinsports.svg#OctinSports") format("svg");
      font-weight: normal;
      font-style: normal;
   }

   p {
      font-family: "OctinSports";
   }
}

Согласно таблице стилей, для всех абзацев должен применяться шрифт Arial, с некоторыми исключениями. Используемый стек шрифтов состоит из популярных шрифтов, встроенных в большинство крупных операционных систем. В общем то, согласно статистике CSSFontStack, шрифт Arial присутствует на 99.84% устройствах с Windows и 98.74% устройствах на Mac. На случай если ни один из перечисленных шрифтов не доступен, в CSS указано общее семейство шрифтов без засечек.

Во второй части style.css описан медиазапрос. Он предназначен для всех устройств с шириной экрана не менее 980px (можно использовать и другую контрольную точку). В этот медиазапрос мы помещаем правило @font-face, которое будет загружать подключённый шрифт, используя устойчивый к ошибкам синтаксис @font-face от Fontspring. Затем мы просто применяем новый шрифт для всех абзацев, заменяя прописанный ранее стиль.

Поддержка браузерами

На первый взгляд это решение кажется отличным, так как позволяет применять подключённый шрифт только для пользователей с большим экраном, которые теоретически не должны столкнуться с проблемой недостаточной пропускной способности. Однако, к сожалению, оно не поддерживается Internet Explorer 10 и старше, а также Firefox 10 и старше. Вам такое поведение может показаться странным, однако на самом деле оно продиктовано спецификацией CSS 2.1, согласно которой @-правила внутри медиазапросов не работают.

Хотя и последняя версии Internet Explorer всё еще не поддерживает такое применение @-правил, компания-разработчик Firefox, Mozilla, добавила его поддержку в версиях после 10. Таким образом, по большому счёту проблема касается только Internet Explorer. Также следует помнить что Internet Explorer 8 и старше не понимают медиазапросы, так что даже если в новых версиях ситуация изменится, проблемы со старыми никуда не денутся.

Как частично решить проблему

Есть ли способ решить проблему поддержки браузером Internet Explorer правил @font-face внутри медиазапросов? Ответ: да, частично.

Как я упомянул в предисловии, с этой проблемой я столкнулся в процессе разработки моего сайта. Мне не было известно о проблеме совместимости с Internet Explorer, так что как и любой добросовестный веб-разработчик я первым делом обратился к Google. Проводя расследование, я наткнулся на статью «Не помещайте @font-face в медиазапрос», из которой я узнал в чём причина проблемы, но не узнал как её решить. Так как найти готовое решение я не смог, пришлось придумать его самостоятельно.

Избавляемся от проблемы в Internet Explorer 9 и старше

Из того, что уже было сказано, получается что проблема состоит только в Internet Explorer, так что можно сосредоточиться на поиске решения, которое будет подходить только для этого браузера. Первым на ум приходит создать отдельный файл CSS, например fonts.css, с всеми правилами @font-face без медиазапросов и использовать условный комментарий. Итак, содержимое fonts.css будет выглядеть так:

@font-face {
   font-family: "OctinSports";
   src: url("fonts/octinsports.eot");
   src: url("fonts/octinsports.eot?#iefix") format("embedded-opentype"),
   url("fonts/octinsports.woff") format("woff"),
   url("fonts/octinsports.ttf") format("truetype"),
   url("fonts/octinsports.svg#OctinSports") format("svg");
   font-weight: normal;
   font-style: normal;
}

Этот подход даёт нам преимущество: для всех браузеров кроме Internet Explorer вес страницы остаётся прежним, если не считать нескольких байтов добавленных условным комментарием. Для IE затраты на загрузку страницы увеличатся вследствие добавления дополнительной таблицы стилей. Так как она содержит всего несколько строчек правила @font-face, после сжатия средний размер файла должен стать всего лишь на 1-2Кб больше. В большинстве случаев это приемлемый компромисс.

Вот сжатая версия кода для реализации этого подхода:

<!--[if IE]>
   <link rel="stylesheet" href="css/fonts.min.css">
<![endif]-->

Это простое решение, но его нельзя считать исчерпывающим, ведь, как вам наверное известно, Internet Explorer 10 не поддерживает условные комментарии, так что он наш код с условным комментарием просто проигнорирует. Проблема еще не решена.

Решение для проблемы с Internet Explorer 10

Для Internet Explorer 10 мы используем менее изящный подход, нам придётся применить хак. Если точнее, мы будем использовать хак построенный на JavaScript; он описан в статье CSS-хаки для IE10. Он определяет что используется IE10 и проверяет является ли ширина окна браузера равной или большей 980px. Если эти условия соблюдены, в элемент <head> страницы добавляется всё та же таблица стилей fonts.min.css. Помните что поскольку хак работает благодаря JavaScript, он, само собой, не будет работать если JavaScript отключён.

<!--[if !IE]><!-->
   <script>
       if (Function('/*@cc_on return document.documentMode===10@*/')() && window.innerWidth >= 980) {
          var link  = document.createElement('link');
          link.rel  = 'stylesheet';
          link.href = 'css/fonts.min.css';
          document.getElementsByTagName('head')[0].appendChild(link);
       }
   </script>
<!--<![endif]-->

Как это решение работает при применении подхода отзывчивого дизайна?

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

Пользователи мобильных устройств

Прежде всего посмотрим на самую свежую статистику (июнь, 2013) использования браузеров на мобильных устройствах, предоставленную StatCounter. На странице по ссылке можно увидеть следующую статистику:

  1. Android: 29.06%
  2. iPhone: 22.77%
  3. Opera: 16.06%
  4. UC Browser: 9.89%
  5. Nokia: 7.38%
  6. Chrome: 3.23%
  7. BlackBerry: 3.11%
  8. NetFront: 2.40%
  9. iPod Touch: 2.21%
  10. Другие: 3.9%

Важным моментом в этой статистике является то, что Internet Explorer в ней отсутствует, он входит в пункт «Другие». Тем не менее, благодаря Крейгу Баклеру (Craig Buckler) из SitePoint, я узнал что согласно данным StatCounter, на IEMobile (всех версий) приходится 1.4% пользователей. Значит используя правило @font-face в медиазапросе мы достигаем нашей цели отображать базовый шрифт как минимум для 98.6% пользователей мобильных устройств.

Крейг мне также написал что по данным NetMarketShare 1.31% использования мобильных браузеров приходится на IE9, а на IE10 — 1.0%. Статистика, конечно же, может отличаться в зависимости от сайта, однако общее впечатление у нас сложилось.

Теперь давайте рассмотрим две самые популярные мобильные версии Internet Explorer: 9 и 10.

Как мы увидели в предыдущем разделе, для IE10 мы используем код JavaScript, который определяет ширину окна браузера. Если на устройстве включена поддержка JavaScript и окно браузера меньше 980px, файл fonts.min.css не будет добавлен. В противном случае, если JavaScript не поддерживается, код не сработает и подключённый шрифт не будет загружен и применён.

С IE9 ничего не поделаешь: таблица стилей будет загружена и подключённый шрифт будет применён в любом случае. Однако с этим столкнется только половина пользователей IEMobile.

Подведём итог: подключённый шрифт не применяется в 99.5% случаев, и только в IE9 ничего нельзя поделать. Мне кажется это отличный результат.

Пользователи настольных компьютеров

Как и в предыдущем разделе, давайте взглянем на самую свежую статистику (за июнь, 2013) использования браузеров на настольных компьютерах. Статистика по настольных компьютерах следующая:

Так как мы оставили правило @font-face внутри медиазапроса, наш веб-сайт оптимизирован под все браузеры, которые поддерживают и медиазапросы (сюда не входит IE8 и старше) и @font-face в медиазапросах. Как мы увидели, в этот диапазон входят все браузеры кроме Internet Explorer. То есть, мы получаем достаточную оптимизацию для 74.58% пользователей, неплохо для начала.

Для Internet Explorer 6-9 подключённый шрифт по нашему желанию будет загружаться с помощью условного комментария. Значит к предыдущему количеству пользователей можно добавить ещё 15.54%, в результате получаем 90.12%.

Что касается Internet Explorer 10, так как таблица стилей загружается с помощью JavaScript, подключённый шрифт загрузится у тех, у кого активирован JavaScript. Я не могу привести статистику для этого случая, но количество пользователей с отключённым JavaScript не должно превышать 0.5%.

Итого, шрифт применяется грубо говоря в 99.5% случаев. Ещё один отличный результат.

Заключение

Подключённые шрифты могут сделать сайт более привлекательным, их использует все большее количество разработчиков и дизайнеров. Однако не следует забывать об оптимизации под мобильные устройства, ведь на них приходится всё большее количество трафика. Как видно из этой статьи, можно использовать подход «сначала мобильные» для веб-шрифтов и поместить @font-face в медиазапрос параллельно с несколькими хитростями для Internet Explorer. Этому приёму можно доверять, ведь она надёжен и позволяет обеспечить хорошую поддержку для 99.5% пользователей мобильных устройств и настольных компьютеров.

Если вы заметили ошибку, вы всегда можете отредактировать статью, создать issue или просто написать об этом Антону Немцеву в skype ravencry.

Aurelio De Rosa
Автор:
Aurelio De Rosa
GitHub:
AurelioDeRosa
Twitter:
@AurelioDeRosa
LinkedIn:
aurelioderosa
Наталья Фадеева
Переводчик:
Наталья Фадеева
вКонтакте:
natatik_l
Twitter:
@very_busy_girl
GitHub:
NatalieF

Комментарии (8 комментариев, если быть точным)

Автар пользователя
AntonMMF

Впервые слышу о проблеме, описанной здесь.

У меня в проектах самый первый подключаемый файл является style.css, в котором в самом начале прописан @font-face. И никогда таких проблем не возникало.

Что я делаю не так?

Автар пользователя
SilentImp

А в каком городе ты живешь? Столице? Небось и интернет на мобильном — полновесный 3G? В таком случае проблему ты не увидишь. Но если ты живешь совсем не в столице и 3G это слухи и происки монархистов, то задержка будет. И будет ощутимой. Даже по поводу этого сайта жаловались. Я, правда, просто решил отказаться от web-шрифтов, что бы сохранить единообразие представления. Впрочем, с интернетом от life:) я ее и находясь в Киеве частенько наблюдаю.

Автар пользователя
f0rmat1k

Там небольшая ошибка про фф 10. Сначала сказано, что он не тянет, потом наоборот.

Автар пользователя
smolnikov

@AntonMMF, советую попробовать открыть, ну, скажем, ленту.ру, пока едете в поезде. Контент вроде бы есть, но его как бы нет. http://cl.ly/image/1i3X1j3n1I2K

Автар пользователя
AntonMMF

На мой взгляд ходить по сайтам через EDGE/GPRS то ещё извращенство. По принципу плачущих колющихся мышей.

Автар пользователя
SilentImp

AntonMMF так выбора часто просто нет. Альтернатива есть в крупных городах. f0rmat1k пытаюсь найти противоречие. Можете уточнить? Было бы здорово исправить.

Автар пользователя
f0rmat1k

Однако, к сожалению, оно не поддерживается Firefox 10 и старше и чуть ниже Mozilla, добавила его поддержку в версиях после 10

Я так понимаю речь идет об одном и том же — о поддержке фонтфейса в медиазапросе. Сначала написано, что оно в фф 10 и выше не работает, затем противоположное.

Автар пользователя
f0rmat1k

Парсер повел себя несколько неожиданно. Первая строка цитату — это утверждение №1, вторая строка относится ко второму.