Примечание: ниже расположен перевод статьи "Inline Images with Data URLs", в которой рассматривается вопрос о внедрении картинки на веб-страницы при помощи data:URI
. Эта схема позволяет вставить код картинок прямо в (X)HTML-страницу без обращений к внешним файлам, что уменьшает общее количество HTTP-обращений к серверу. Мои комментарии далее курсивом.
Встроенные (inline) изображения используют схему data:URI
для внедрения прямо в тело веб-страницы. Как было определено в RFC 2397, такие URI предназначены для вставки небольших объектов как «непосредственные» данные. Такие объекты должны рассматриваться так же, как и любые другие внешние файлы. Использование встроенных изображений позволяет сэкономить HTTP-запросы к внешних ресурсах.
Хотя Opera 7.2+, Firefox, Safari, Netscape и Mozilla поддерживают data:URI
, Internet Explorer 5–7 совсем нет. Однако, сообщается, что Internet Explorer 8 будет поддерживать эту схему, так как проходит Acid2 тест, что позволяет использовать data:URL
как реальную альтернативу для внедрения небольших декоративных изображений. Существует также несколько приемов для поддержки старых версий Internet Explorer.
Вы уже имеете представление о других схемах URL в своих переходах по интернет-страницам, например, о http:
, ftp:
и mailto:
. Схема data:URL
предоставляет способ для внедрения «непосредственно данных» точно так же, как если бы они были подключены через вызовы внешних файлов. Синтаксис у data:URL
следующий:
data:[<тип данных>][;base64],<данные>
В случае простых изображений вам нужно указать mime-тип для них (например, image/gif
), за ним идет base64-представление бинарного файла с изображением. Ниже приведен пример (переводы строк добавлены, чтобы не разрывать страницу, на самом деле, их нет):
<img src="data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0j vb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAA Re8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0Cc guWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7" width="16" height="14" alt="внедренная иконка папки"/>
В результате вы получите следующее изображение иконки папки (частичный скриншот ниже):
Такие изображения, внедренные в HTML-страницы, не кешируются для повторного использования, и они не кешируются от странице к странице (это логично: ведь нам нужно каждый раз загрузить HTML-код для отображения этой картинки, они будут кешироваться только с HTML, их содержащим). Однако, CSS кешируется браузерами, и такие изображения могут быть повторно использованы вместе с использующим их селектором, например:
ul {list-style:none;} ul > li { margin:0 0 .1em; background:url(data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0j vb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1 Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsV MkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7) top left no-repeat; height:14px; text-indent:1.5em; } </style>
Теперь иконка папки будет повторяться для каждого вхождения LI
(или можно также использовать соответствующий класс или ID
).
<ul> <li>Testing inline images, one</li> <li>Two</li> <li>Three</li> </ul>
Что выглядит в Firefox примерно следующим образом (частичный скриншот):
С описанным выше подходом для подключения изображений связано две основные проблемы. Во-первых, вам нужно пересчитывать base64-представление изображений и редактировать CSS-файл каждый раз, когда само изображением меняется. Также IE до версии 7 включительно не поддерживает встроенных изображений. У первой проблемы есть простой решение на PHP:
<?php echo base64_encode(file_get_contents("../images/folder16.gif")) ?>
Этот код читает файл с изображением и автоматически преобразовывает его на сервере в base64. Однако, это простота этого решения повлечет некоторую дополнительную нагрузку на сервер. Как вариант можно рассмотреть автоматический пересчет всех картинок и вставка их в CSS-файл, например, раз в 5 минут по необходимости (если файл с изображением изменился). Дополнительно нужно будет озаботиться, чтобы сбросить кеширование для самого CSS-файла.
Существует два способа обойти отсутствие в IE поддержки data:URL
. Используя распознавание браузеров (например, с помощью условных комментариев, ведь речь идет только про IE) можно просто отображать внешнее изображение для IE и встроенные изображения для остальных браузеров. Или вы можете использовать JavaScript для эмуляции этой поддержки в IE, но эта техника потребует довольно значительного объема JavaScript-кода. Вышеприведенный PHP-код позволяет легко вставить base64-аналог изображения (можно расширить этот пример, чтобы, например, распознавать заголовки, отправляемые браузером серверу и только для IE выводить URL для изображения, для остальных же кодировать его в base64):
ul {list-style:none;} ul > li { margin:0 0 .1em; background: url(data:image/gif;base64,<?php echo base64_encode(file_get_contents("../images/folder16.gif")) ?>) top left no-repeat; height:14px; text-indent:1.5em; } </style>
Когда ваш сервер анализирует CSS-файл, он автоматически перекодирует бинарный файл изображения в base64 и отправит эти данные внутри CSS-файла. Следующим шагом будет добавление распознавания браузеров для отправки изображения только IE, и встроенных изображений всем остальным. Это можно сделать либо внутри CSS-файла с PHP-кодом, либо с помощью условных комментариев, например:
<!--[if gte IE 5]> <style type="text/css" src="ie.css"> <![endif]--> <!--[if !(IE)]> <style type="text/css" src="notie.css"> <![endif]-->
В файле ie.css
должно быть нормальное обращение к картинке, например:
ul > li { margin:0 0 .1em; background: url(/images/folder16.gif) top left no-repeat; } ...
Лично мне вышеприведенный код кажется сомнительным: все браузеры, кроме IE, посчитают, что CSS-файлы закомментированы и вообще к ним не обратятся. Поэтому я бы советовал оставить комментарии только для первого файла и переместить его вызов в конец, чтобы он переопределял общие стилевые правила.
С помощью data:URL
вы экономите HTTP-запросы. Вместе с техникой CSS sprites data:URL
могут значительно уменьшить число HTTP-запросов. Будет весьма интересно посмотреть, если удастся использовать data:URL
в сочетании с USEMAPS или сделать CSS sprite с помощью data:URL
. Итак, краткий список плюсов данного метода:
Встроенные изображения не поддерживаются в Internet Explorer 5–7, хотя сообщается, что версия 8 их поддерживает. Текстовое base64-представление данных также занимает больше, чем бинарное изображение. В наших тестах base64-данные были на 39–45% больше бинарного аналога, но gzip-сжатие позволяет уменьшить разницу до 89%. Предварительная оптимизация изображений перед base64-кодированием позволяет уменьшить их размер пропорционально.
Также существует ряд ограничений на размер встроенных изображений. От браузеров требуется поддерживать только URL длиной до 1024 байтов, в соответствие с вышеупомянутой спецификацией RFC. Однако, браузеры более либеральны к пользователям в том, что они принимают. Например, Opera ограничивает data:URL
до примерно 4100 символов. Firefox поддерживает data:URL
вплоть до 100Кб. В итоге, эта техника подходит больше для небольших по размеру изображений. Краткий список минусов:
Ниже приведено несколько примеров, которые вы можете проверить в своем браузере. Все они отражают вышеприведенный код.
Наиболее разумным будет, мне кажется, подход, не увеличивающий общее число CSS-файлов, т.е. использующий характерные хаки для IE, чтобы только для него подключить фоновые изображения. Для IE версий 6 и ниже можно использовать * html
, для IE 7, к сожалению, этот хак уже не работает, поэтому используем *+html
(спасибо за дополнение Bueno). В итоге, вышеприведенный пример будет выглядеть примерно так:
* html ul li { background-image: url(/images/folder16.gif); } *+html ul li { background-image: url(/images/folder16.gif); }
Также возможно автоматическое кодирование изображений, которые выводятся в base64, автоматически при изменении этих изображений (для этого потребуется простой скрипт, который проверяет, обновились ли соответствующие файлы, если обновились, то перезаписывает их представление в CSS-файле, заодно и меняет хеш-строку для подключения этого файла в HTML, чтобы избежать кеширования.
Для включения небольших графиков прямо в HTML-код прекрасно подойдут условные комментарии, когда для ряда браузеров изображение выводится в base64, а для остальные в виде IE подключается через условные комментарии. Если использовать связку относительное позиционирование родителя абсолютное позиционирование дочернего элемента, то IE будет просто выводить картинку из внешнего файла поверх непонятного (для него) объекта. Например, так:
<div id="chart"> <img src="data:image/png;base64,..." alt="График" title="График"/> <!--[if IE]> <img src="chart.png" alt="График" title="График"/> <![endif]--> </div>
Оба примера использования можно посмотреть на webo.in: на главной странице график выводится прямо в теге img
, фоновый CSS sprite в CSS-файле записан также в base64-кодировке. Если у кого-то не отображается какая-либо картинка, напишите, пожалуйста, в комментариях будем думать над решением.
Хочу подчеркнуть, что решение об использовании data:URL
должно приниматься на основе статистики использования браузеров для просмотра сайта (для webo.in доля IE составляет меньше 20%, что позволяет использовать более прогрессивные методы для оптимизации скорости загрузки).
С релизом Internet Explorer 8 data:URI
должны стать реальной альтернативой существующим методам вывода изображений. Вы можете вставить небольшие изображения прямо в тело страницы с помощью data:URL
для экономии числа HTTP-запросов. data:URL
является удобным способом для создания автономных веб-страниц, которым не требуются никакие внешние объекты для полного своего отображения.