Быстрая загрузка веб-шрифтов на адаптивных сайтах

Давным-давно каждый сайт использовал для отображения текста только такие шрифты, как Arial, Verdana, Garamond или Times New Roman, потому что только эти шрифты наверняка были установлены почти на любом компьютере. Но эти времена позади. Веб-шрифты распространяются по всему интернету, но мы все еще толком не знаем, как загружать их эффективнее.

pagespeed99

Эта статья – моё простое руководство о том, что делать, чтобы предложить оптимальный пользовательский опыт без необходимости избегать «дорогих украшений» (ака веб-шрифтов)

0. Если лень читать полностью

Суть метода:

  1. Используем шрифты только в формате woff
  2. Другие браузеры получает старые «безопасные» шрифты
  3. Загружаем шрифт в бинарном формате и оптимизируем его
  4. Отдаем шрифты сами
  5. Отдаем их в качестве CSS-файловURIs с закодированными в base64 данными
  6. Если у пользователя нет шрифта, загружаем его асинхронно и сохраняем в localStorage
  7. Иначе загружаем его из localStorage без обращения к серверу.
  8. Радуемся, потому что ваш сайт отображается намного быстрее, а ваши пользователи получают намного больше удобства

Для тех, кто всё ещё читает, вот мои разъяснения, насчет верхних пунктов.

Обновлено – 09.10.2014

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

  1. Демо-страница: Загрузка из шрифтов Google.
  2. Страница тестирования скорости: загрузка из шрифтов Google (79/100)
  3. Демо-страница: асинхронная загрузка и получение позже из localStorage.
  4. Страница тестирования скорости: асинхронная загрузка/ localStorage (100/100)

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

Согласно caniuse, 84% используемых браузеров поддерживают формат woff. Исключением являются старые браузеры – IE8 и встроенные браузеры старых андроидов. Следовательно, вполне достаточно предоставить веб-шрифты только современным браузерам с поддержкой формата woff. А старые браузеры могут довольствоваться запасным решением в виде шрифта Arial, например. А также пользователи будут вам признательны за то, что ваш сайт быстрее отображается в браузере. Просто постарайтесь найти то, что лучше подходит для дизайна вашего сайта.

2. Не используйте внешние источники шрифтов, такие как Google Fonts или Typekit

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

3. Необходимость лицензии

Внимательнее выбирайте шрифт, который вы загружаете себе. К сожалению, не все лицензии позволяют это делать. Но к счастью, многие позволяют — как те, что с открытыми исходниками. Например, такие как Open Sans или Source Sans Pro. Когда вы выберете шрифт, скачивайте «двоичные» файлы (форматов otf или ttf)

4. Оптимизация, уменьшение размера, генерация CSS

Заходите на: генератор веб-шрифтов Font Squirrel.

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

Важно выбрать правильный вариант, чтобы сгенерировать CSS-файл, который содержит шрифты, закодированные в base64. Это будет файл, который вам действительно нужен.

5. Отдача CSS-файла

Файл может быть довольно большим (вплоть до 100-300кб) в зависимости от выбора кодировок и других опций. Поэтому важно правильно сжать файл с помощью gzip и установить строгое кеширование во время его получения пользователями.

К счастью для ваших пользователей, вам будет нужно отдать им этот файл только один раз. В первый раз, когда у пользователя не окажется этого шрифта, браузер загрузит его асинхронно и поместит в localStorage. В это время пользователи с медленным соединением могут видеть, как браузер перерисовывает «запасные» шрифты в ваши веб-шрифты, но это происходит не более одного раза. А большинство пользователей вообще ничего не заметят.

Начиная со второй загрузки страницы, вы будете загружать только CSS-файл из localStorage. Который загружается достаточно быстро (5-50мс). Пользователи не увидят даже мерцания, потому что все действия синхронны, но потребуют всего пары миллисекунд.

6. Покажите мне код

После того, как мы сохранили файл в localStorage, этому методу необходим код только на клиентской стороне. Вот, возьмите:

<head>
...
<script>
(function(){
    function addFont() {
        var style = document.createElement('style');
        style.rel = 'stylesheet';
        document.head.appendChild(style);
        style.textContent = localStorage.sourceSansPro;
    }

    try {
        if (localStorage.sourceSansPro) {
            // The font is in localStorage, we can load it directly
            addFont();
        } else {
            // We have to first load the font file asynchronously
            var request = new XMLHttpRequest();
            request.open('GET', '/path/to/source-sans-pro.woff.css', true);

            request.onload = function() {
                if (request.status >= 200 && request.status < 400) {
                    // We save the file in localStorage
                    localStorage.sourceSansPro = request.responseText;

                    // ... and load the font
                    addFont();
                }
            }

            request.send();
        }
    } catch(ex) {
        // maybe load the font synchronously for woff-capable browsers
        // to avoid blinking on every request when localStorage is not available
    }
}());
</script>
...
</head>

7. Чего мы добились

  1. Устранили как минимум один, а скорее всего множество блокирующих запросов
  2. Максимум одно мерцание у пользователя, во время замены «запасного» шрифта на веб-шрифт (первое посещение, первый запрос)
  3. Ускорили время отображения на первой странице запроса
  4. Улучшили показатели скорости в Google Page Speed Insights и WebPageTest.org

8. Увидеть это в действии

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

В этой статье всё ещё отсутствуют некоторые мелкие подробности. Если у вас есть вопросы или отзывы, то добро пожаловать в комментарии.

Обновлено – 10.11.2014

Пользователь Twitter’a @Kseso, проинформировал меня о другом подходе, который также получает 99/100 баллов в Google Page Speed Insights.

Я выступаю против этого подхода, потому что он надолго задерживает отображение текста. Поэтому давайте более детально расссмотрим, что происходит в этом методе.

  1. Мы сразу же определяем семейство шрифтов в обычном HTML-файле:
    <head>
    ...
    <style>
    @font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro'),
      local('SourceSansPro-Regular'),
      url(http://fonts.gstatic.com/s/sourcesanspro/v9/ODelI1aHBYDBqgeIAH2zlBBHWFfxJXS04xYOz0jw624.woff) format('woff');
    }
    </style>
    ...
    </head>
    
    
  2. Браузер не будет получать файл шрифта до тех пор, пока не убедится, что этот шрифт вообще понадобится где-либо на странице.
  3. Браузер дождется окончательного построения DOM и CSSOM
  4. Браузер начнёт получать файл шрифта из Google Fonts (заметьте, что для fonts.gstatic.com требуется лишний DNS-запрос).

    gfonts-timeline

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

  5. Если вам этого мало, большинство браузеров просто отобразят пустой текст на месте загружаемого шрифта:
    1. Только IE начнёт отображение немедленно с «запасными» шрифтами
    2. Firefox и Chrome35+ ждут полной загрузки шрифта в течение трех секунд (а затем отображают «запасной» шрифт)
    3. Safari и Chrome до 35-й версии ждут полной загрузки шрифта без каких-либо таймаутов.

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

Больше информации можно найти в блоге Ильи Григорика.

Так же я создал тестовую страницу, где вы можете проверить это сами.

Перевод статьи Loading webfonts with high performance on responsive websites с сайта bdadam.com, c разрешения автора —
Адама Береша-Дика
.

P.S. Это тоже может быть интересно:

32 Комментарии

  1. AntonMMF

    А потом приходит JPG (с) не помню кто

  2. Дамир
    1. Максим Усачев (Автор записи)

      Спасибо, поправили!

  3. Softlink

    Base64 можно применять только тогда, когда шрифт точно должен быть на странице. Видимо, про это и писал "Kseso". Иначе файл шрифта загрузится в любом случае, используется он на странице или нет. При этом base64 весит обычно больше оригинального файла woff.

    1. SelenIT

      Как я понял, Адам напирает на то, что собственно грузиться файл будет только для первой страницы, а в дальнейшем будет браться даже не из кеша, а из localStorage (вообще без запроса к серверу и ожидания 304-го ответа, т.е. практически мгновенно). Так что даже если он не понадобится сразу, то как только понадобится, он будет доступен сразу, не вызывая ни секунды ожидания (особенно неприятного в вебкитятах, где во время этого ожидания текст выводится белым по белому). А разница в размерах файла довольно неплохо нивелируется gzip-ом.

      Лично меня эти аргументы скорее убеждают:)

      1. Softlink

        Тогда надо быть точно уверенным, что пользователь дойдет до страницы со шрифтом.

        1. SelenIT

          Ну этот метод всё-таки для случаев, когда шрифт используется активно и помногу :)
           

  4. Ден

    У меня демо с подгрузкой из localStorage мерцает. Причём постоянно. А вот обычная подгрузка работает хорошо без мерцаний.

    38 хром, мак.

    1. Ademaro

      Подтверждаю: с localStorage неприятно мерцает при загрузке страницы (видимо, после загрузки DOM'a, а если HTML большой – вообще будет раздражать, думаю)

      Chrome 40.0.2201.2 canary (64-bit), Safari 8.0
      В FF 32 такой проблемы нет.

      1. SelenIT

        Похоже, это событие не загрузки DOM-а, а его изменения (добавление элемента <style>), которое Хром почему-то обрабатывает асинхронно и reflow/repaint происходит в момент, когда что-то уже вывелось на экран и отобразилось шрифтом по умолчанию. Выглядит неприятно, согласен. Но зато на медленном соединении пользователь при первом заходе сможет сразу начать читать текст (пусть и не такой красивый), а не смотреть в белый экран до загрузки шрифта (особенно неприятно в мобильниках, где скорости часто оставляют желать лучшего, а кеш маленький и часто сбрасывается). Что меньшее зло -— вопрос открытый, заодно есть повод поэкспериментировать и попытаться довести подход до ума. Предлагайте идеи!

        P.S. Лично у меня (Chrome 38 на Windows 8.1) все примеры визуально грузятся одинаково:). Какой-то скачок есть, но с чем он связан — с подменой шрифтов или сужением окна из-за появившегося скроллинга — глаз уследить просто не успевает.

  5. Vladimir Sobolev

    Еще можно использовать HTML5 appсache. В manifest файл можно прописать не только имя файла шриста, но и другую статику и обновлять версию своевременно, что избавит от всех запросов к серверу кроме одного — к файлу манифеста. Тестовая страница и замер гугла. Не работает в IE9 и ниже.

    1. SelenIT

      Спасибо за напоминание про appcache, действительно, хорошее и стандартное решение для минимизации сетевых зависимостей. Но верно ли я понимаю, что при первом заходе до загрузки шрифта в вебкитообразных текст не будет виден, как и при вставке гугловских шрифтов в страницу инлайн (метод, предложенный @Kseso и раскритикованный автором статьи)?

  6. Андрей

    А что в этом решении делать, когда шрифт изменится? Придётся, очевидно, встраивать алгоритмы «проверки кэша» в скрипт.

  7. Милчеловек

    Разложите — что и где мне прописать в скрипте для своих нужд: если у меня какой-то другой шрифт, если шрифтов больше одного, что такое localstorage и так далее.

    А то сайт называется «css live», а выходит — для не знающих джаваскрипт, статья бесполезна. Это ведь джаваскрипт, верно?

    1. Максим Усачев (Автор записи)

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

  8. Денис

    Спасибо, статья очень помогла.

    Есть сайт с кастомным шрифтом и всё время бесило мерцание при загрузке, а поправить всё никак времени не было, теперь наконецто поправил.

  9. Николай

    Чем описанный способ (localStorage) лучше жесткого кэширования (cache-control: max-age=360000000, public) в браузере самого шрифта? Браузеры обычно не отправляют 304-запрос, если файл лежит в браузерном кэше.

    1. SelenIT

      Обычно, возможно, разница действительно невелика. Но всё же браузеры не обязаны не отправлять запрос на ревалидацию кэша (и во многих сценариях отправляют, напр. по F5), в варианте с localStorage у нас больше контроля над этим. Ну и немаловажный для многих момент, что не у всех есть доступ к настройкам сервера, а описанный подход позволяет разобраться с проблемой силами исключительно фронтенд-части…

    2. Артем

      Плюсанул бы, да нельзя=) Мне кажется, засовывать шрифты в localStorage, возможно и экономия, но экономия на спичках. Пользователь на сайте, очень редко жмет f5 или ctr+R. И по этому, обычного кеширования, для css файла, в котором шрифт в base64 достаточно. ИМХО.

      1. SelenIT

        Надо еще проверить, при таком подходе тоже может проявиться тот же недостаток, что в методе @Kseso — невидимость текста до момента, когда браузер поймет, что шрифт нужен.

        1. Артем

          Можно, после сборки, поместить шрифт(base64) и основные стили в 1 файл, который будет кешироваться. В том же файле, указать шрифт, как основной на элементе body. И проблем быть не должно. По моему опыту, используя даже googlefonts, разместив его в шапке сайта, проблем с мерцанием нет(если указать шрифт основным, сразу после загрузки шрифта).

  10. Владислав

    Попробвал данный метод — в лисичке убирает мерцание, в хроме — наборот появляется. Причем в хроме сначала грузится fallback шрифт (в моем случае, sans-serif), и после где то пол-секунды нужный,даже если шрифт уже в localStorage.
    Лучшей практикой будет, пожалуй, для хрома пользоваться стандартным кэшем, для файрфокса — ложить в localStorage.

    1. c01nd01r

      У себя в Chrome 35, Win8 такого не наблюдаю.
      После обновления страницы нужный шрифт рендерится сразу, без морганий.

  11. Albert

    Два дня мучался со шрифтами, пока не нашел эту статью. Попробовал методику каких-то ребят из MIT, которые ставили сначала родной шрифт, а потом подгружали из ЖаваСкрипт. В общем сделал как у вас написано, доволен результатом, хоть сам я вообще не верстальщик!

  12. asya

    Адаптируем сайты под мобильные устройства
    Адаптивный сайт решит Ваши проблемы с сайтом:
    -Клиенты уходят с Вашего сайта, не сделав Заказ.
    -У Вас нет покупок с мобильных устройств.
    -Деньги Ваших клиентов достаются конкурентам с мобильной версией сайта.
    -Клиенты не читают важную информацию на Вашем сайте.
    -Клиенту трудно увидеть номер Вашего телефона, чтобы связаться с вами.

    Получи бесплатно макет главной страницы твоего мобильного сайта,
    кликай: http://adapteem.ru/land

    Ваш сайт будет одинаково хорошо смотреться на Iphone, Ipad, Android смартфонах и планшетах!

    По статистике 57% пользователей интернета смотрят сайты с мобильных и планшетов.

    Гарантируем рост конверсии с мобильного трафика или вернем деньги!

    Адаптим: мы увеличим Ваши продажи с мобильного или вернем деньги!

    Звоните: 8 (499) 346-81-06

  13. Александр

    Остановился на шаге с fontsquirrel. На шрифт Гугла ругается вот так

    The font ‘scada.woff2′ is corrupt and cannot be converted

  14. Denis

    Используем шрифты только в формате woff

    Woff жмется хуже всех остальных форматов. В частности сжатый woff будет весить больше, чем сжатый ttf:

    Исходные файлы:

    ║PragmataPro.eot │335708║
    ║PragmataPro.otf │220152║
    ║PragmataPro.ttf │335528║
    ║PragmataPro.woff │155048║

    Сжатые gz (kzip-ом):

    ║PragmataPro.eot.gz   │146730║
    ║PragmataPro.otf.gz   │105043║
    ║PragmataPro.ttf.gz   │146665║
    ║PragmataPro.woff.gz  │154888║

    Сжатые gz (Zopfli —i3000) + deflopt):
    ║PragmataPro.eot.gz   │146537║
    ║PragmataPro.otf.gz   │104714║
    ║PragmataPro.ttf.gz   │146493║
    ║PragmataPro.woff.gz  │154888║

    Otf здесь выглядит очень привлекательно.

    1. SelenIT

      Видимо, от конкретного шрифта зависит (возможно, и от настроек архиватора). Попробовал на одном шрифте из моего текущего проекта — ttf несжатый 344 кБ, сжатый 133, а woff что несжатый, что сжатый — 132:)

      1. Denis

        Да, это точно так. Woff, похоже, жмется очень и очень по разному.

  15. Денис

    Максим здравствуйте.Сколько будет стоить ваша работа если вы исправите все ошибки на сайте?

    1. Максим Усачев (Автор записи)

      Денис, здравствуйте! К сожалению нисколько, потому что в данный момент я не беру никакие заказы. И в ближайшее время не планирую. Поэтому советую обратиться на наш форум (htmlforum.ru ), вам там обязательно помогут!

  16. Виктор

    Приветсвую, Максим. Тема это у вас уже старенькая, но до сих пор актульная.
    Вот не могу привести шрифт от гугл в порядок. Всю статистику портит.
    Могли бы помочь шрифты сделать по описанному вами методу?
    Пробовал закружать чтоб все как у гугл, только с моего хоста шло. Работает, но только на компах, а на мобильных версиях уже нет и на айпаде нет.
    Будет ли так же с вашим методом или тогда будет все нормально? Вот шрифты
    https://fonts.googleapis.com/css?family=Exo+2:400,500,700,900&subset=latin,cyrillic

Оставить комментарий

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

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

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