Xiper

Встраиваем изображения — data:URL

Автор: Александр Головко и Егор Скорняков Дата публикации:

Как ты, конечно, знаешь, браузер, встретив в HTML тег img, спешит отправить на сервер запрос для загрузки соответствующей картинки. Примерно так же обстоят дела и с CSS-свойством background-image. В общем, как только встречаем картинку — имеем дополнительный запрос (а это время и трафик, в том числе, потраченный на пересылку HTTP заголовка — около килобайта).

Вот такое вот поле для деятельности оптимизатору. Раз каждая картинка — это отдельный запрос, значит, чтобы уменьшить число запросов, нужно уменьшить число отдельных картинок. Поскольку просто выбросить картинки нам никто не даст, остается их объединять — склеивать разные изображения в один файл. Загружаются склеенные картинки одним запросом, а уже потом выбираются нужные участки (благо в CSS есть свойство background-position). Этот типичный подход описан в статье Спрайты: меньше картинок — больше скорость.

Схема data:URL

Но есть и другой вариант. А что, если картинки не клеить между собой, а внедрять прямо на место их использования — непосредственно в HTML и CSS файлы? Конечно, сами файлы при этом несколько «распухнут» — увеличатся в размерах, но зато все загрузится за один запрос. Выигрыш на заголовках может быть весьма ощутимым! И, как ты увидишь ниже, не только на заголовках.

Технически, такая «вклейка» возможна. Базируется она на схеме data:URL. Эта схема позволяет внедрить на веб-страницу данные так, как если бы они были подключены с помощью вызова внешних файлов. Оговорюсь, внедрение возможно не в произвольном месте, а именно в URL (например, в атрибуте src, тега img).

Сразу предупрежу — метод не панацея. Имеет ряд существенных ограничений. Но, давай по порядку.

Как это выглядит?

Все очень просто. Имеем следующий синтаксис:

data:[MIME-тип][;base64], данные 

где:

  • MIME-тип — тип встраиваемых данных (мы будем встраивать рисунки, поэтому, скорее всего, будет что-то типа image/gif или image/png);
  • base64 — означает, что данные закодированы в base64 (если параметр не указан, считается, что данные закодированы в ASCII);
  • данные — собственно набор байт — закодированное изображение.

На практике получатся примерно такие (или во много раз более длинные) громоздкие, но вполне валидные конструкции:

<img
src="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw
AAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz
ByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp
a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJl
ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uis
F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH
hhx4dbgYKAAA7"
height="16px" width="16px" alt="какая-то картинка" />
li { 
background: url('data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
g9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC') no-repeat; }

А что с кроссбраузерностью?

Закономерный вопрос. В настоящее время подавляющее большинство браузеров поддерживают эту технологию. Ни с Firefox, ни с Opera, ни с Safari, ни с IE8+ никаких проблем быть не должно.

Для IE6-7 существует альтернативное решение вставки изображений в виде mhtml-включений. Так что можно сказать, что все популярные браузеры позволяют использовать внедрение изображений.

Как обычно, не откладывая в долгий ящик, демо-пример странички с data:URL для фоновых картинок (CSS) и для тега img (HTML).

Проверено в:

  • IE 6-8
  • Firefox 3
  • Opera 9.5-10
  • Safari 4
  • Chrome 8

Как получить код?

С кроссбраузерностью разобрались, пример посмотрели. Теперь самое время, что бы кто-нибудь сказал: «Стоп! Что ты там за символы понавставлял в примере?! Где ты их взял? У меня же просто картинка! Файлик…».

Не беспокойся. За нас уже поработали. Существуют готовые сервисы, которым можно «скормить» файл-картинку и получить соответствующий ей код.

Про размеры картинок

Так как картинка вставляется в URL, на размер кода накладываются некоторые ограничения. Вообще говоря, по спецификации, браузеры обязаны поддерживать URL не менее 1Kb. На самом деле ситуация гораздо лучше. В ходе эксперимента выяснилось, что блок кода картинки до 32Kb можно смело использовать во всех популярных браузерах (FF, Opera, Chorme, Safari, IE6+).

При размере больше 32Kb пасует IE8. Но, если для IE8 использовать не data: URL, а MHTML-включение (как для IE6-7), то можно использовать код до 64Kb.

Важная оговорка! Цифры, приведенные выше, относятся именно к размеру base64-кода картинки. Фактический размер изначального изображения должен быть примерно на треть меньше. Таким образом, имеем безопасное ограничение для размера встраиваемой картинки примерно 20Kb.

В чем сила, брат?

Итак, можно с помощью специального сервиса превращать картинки в строки кода и вставлять их в HTML/CSS. Но это же уйма дополнительной работы! Для чего это все?

Преимуществ метода достаточно много. Вот перечень показавшихся наиболее существенными:

  • все внедренные данные попадают на страницу в результате одного запроса — даже на простенькой странице так можно выиграть десятки килобайт на заголовках HTTP, то есть уменьшить нагрузку на сеть и не терять время на ожидание обмена информацией между сервером и клиентом при каждом запросе;
  • некоторые браузеры имеют ограничение по количеству параллельных подключений к серверу, встроенные данные освобождают подключения для загрузки другого контента;
  • меньше используется файлов — значит меньше файлов попадет в кеш, в некоторых ситуациях это может быть важно;
  • дополнительная функциональность — например, браузер может перекодировать в data:URL картинку, находящуюся в буфере, и вставить ее в HTML поле ввода;
  • шаблоны e-mail сообщений могут содержать картинки, например, подпись или фоновый рисунок, без необходимости использовать вложения.

Обратная сторона медальки

Недостатков тоже хватает:

  • трудоемкость при разработке и поддержке. Мы не просто пишем адрес картинки, а еще и тратим время, кодируя/декодируя ее;
  • утверждается, что закодированные в Base64 данные примерно на треть больше по размеру, чем исходный файл изображения. Этот негативный момент можно устранить, если использовать gzip сжатие — такие данные будут хорошо жаться;
  • для HTML теряется выгода от кеширования — внедренные картинки, являясь единым целым с HTML-страницей, перезагружаются каждый раз, когда перезагружается документ;
  • браузеры имеют ограничения по длине URL, что определяет максимальный размер данных. То есть метод неприменим для больших картинок;
  • данные включаются как простой поток, и многие среды обработки не могут поддерживать контейнеры (вроде multipart/alternative или message/rfc822), чтобы обеспечить большую гибкость, типа метаданных, сжатия данных или согласования контента по языку.

Где применять?

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

Очевидно, что выигрыш от использования data:URL для CSS существенно больше, чем для HTML (где теряем выгоды от кеша и получаем дополнительный геммор с IE6-7). Так же имеем очень существенную оговорку о максимальном размере закодированного файла (да еще для разных браузеров он разный).

Вывод напрашивается сам собой: встроенные, при помощи data:URL, изображения имеет смысл использовать в CSS, для небольших фоновых картинок — получим выигрыш в быстродействии.

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

О производительности

update by Ksayri Применение data:URL способно существенно снизить (до 10 раз) производительность некоторых браузеров. В частности это касается Firefox (который тратит очень много ресурсов на обработку base64) и IE6-7 (которым приходится иметь дело с mhtml). Чем больше будет data:URL на странице, тем больше будет тормозить.

Поэтому сейчас оптимальным решением будет приметь сначала CSS спрайты, а затем преобразовывать минимальное количество спрайтов в data:URL.

Материалы:

  • Data:URI CSS Sprites — современный подход к генерации CSS спрайтов
  • Data:URL средствами браузера
  • Data URIs, MHTML and IE7/Win7/Vista blues
  • data:URI и производительность, или как замедлить Firefox в 10 (десять) раз