Что в интернет попало…
Костя Коломеец
Кроссбраузерный data URI в CSS-файлах (многабукв)
Прелюдия
Некоторое время назад, я нашёл способ, использования data URI в Internet Explorer. Data URI — специальный вид URL, который включает в себя код самого объекта. Например, таким образом можно внедрять изображения прямо в код
Выглядит такой HTML вот так:
<img src="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP…и так далее" />Где «data» — это протокол URI, image/gif — тип объекта (картинка GIF), base64 — тип кодирования, после запятой идёт сам код картинки.
Такой вид URI понимают сейчас все современные браузеры, включая Internet Explorer 8 (правда, со многими ограничениями). Плохо то, что Internet Explorer 7 и ниже этого не поддерживает, а доля этих версий настолько велика (около 50% на данный момент по данным LiveInternet), что до недавнего времени data URI использовалась крайне редко.
Я, увлёкшись исследованием малодокументированного протокола mhtml (MIME HTML), поддерживаемого в браузерах Microsoft с пятой версии, в одном из экспериментов разобрался как внедрить объект в тело
Вообще mhtml был придумал для адресации внутри так называемых
Типичный
mhtml:http://example.net/index.html!fhhryregdy4gereГде после «mhtml» идёт обычный
В итоге, когда мне пришла эта идея, я совместил оба способа так, чтобы Internet Explorer видел файл как
Специфика HTML допускает переносы, в том числе и внутри data URI, поэтому мне удалось задуманное относительно быстро. В CSS всё сложнее, а тема использования data URI в CSS, как оказалось, актуальнее, чем для HTML. Например, в книге Николая Мациевского «Разгони свой сайт» сделана попытка расширения моего способа на CSS, к сожалению, менее удачная, чем хотелось бы: требуется включение закодированного объекта два раза.
Фуга
Итак, мне захотелось посмотреть, не получится ли расширить мой способ на CSS, не прибегая к включению закодированного файла два раза. Причём, сфера тут уже, подключаемый к CSS объект это, в 99,99% — картинка.
После немногочисленных экспериментов, оказалось, что оторвать закодированный объект от начала data URI не представляется возможным, что мешает использованить mhtml — там заголовок и кодированный объект должны отделяться пустой строкой.
Тем не менее, других способов побороть IE я не видел и потому продолжал эксперименты. Несколько слов о том, что такое base64. Base64, по сути, анахронизм, доставшийся нам от электронной почты на заре её зарождения. Письма тогда ходили исключительно в латинице и все почтовые системы полагали, что никаких других символов в письмах не бывает.
Таким образом, когда встала задача передавать в письмах
Хорошие новости, заключаются в том, что браузеры игнорируют в кодированной строке символы, которые не входят в упомянутые 64. Можно было ожидать, что браузеры вообще откажутся разбирать такую строку.
Итак, строка data URI начинается
Из вышесказанного следует, что нужно
Оставим в покое XBM, BMP, ART, WMF/EMF, JPEG200 и прочую экзотику, поддерживаемую браузерами, и остановимся на триплете JPEG, GIF, PNG. Честно сказать с форматом GIF я знаком плохо, а JPEG и PNG исследовал несколько лет назад довольно подробно.
JPEG и PNG состоят из секций. В общих чертах, сначала идёт заголовок файла, потом сами секции, в формате (с некоторыми вариациями) «имя секции», «длина секции», «конец секции». И у JPEG, и у PNG есть секции для произвольного содержимого. У JPEG это COM и APPn, у PNG — iTXt, tEXt и zTXt. Кстати, и у GIF тоже есть похожее место — Application Extension.
Отсюда идея: Internet Explorer, декодировав файл с начала строки, получает заголовок с секцией из содержимого, куда помещается заголовок для остальных браузеров и мусор, оставшийся от декодирования начала data URI, остальные браузеры должны пропустить заголовок для IE и начать декодирование с data URI.
Получаем, на примере JPEG:
FF D8 — заголовок JPEG для IE FF E0 xx xx — секция APP0, куда прячется всё до данных изображения, «;background-color:url(data:image/jpeg;base64,» — это видят остальные браузеры FF D8 — начало JPEG для остальных браузеров «данные изображения» — это место видят уже все браузеры
Все бинарные данные выравниваются и кодируются (строка начала
В моём примере такой CSS выглядит вот так:
/9j/4AAs;background-image:url(data:image/jpeg;base64;BOLKNOTE.RU,/9j/4AAC…Легко увидеть, как видит этот стиль браузер: «/9j/4AAs» кажется ему ошибочным атрибутом (его, кстати, можно взять в комментарий), а «;» — разделителем атрибутов. И хорошо просматривается («/9j/AA») двойной старт заголовка
Остальное должно быть понятно из примера («!ie» — CSS hack, делающий стиль видимым только для IE), как это выглядит в браузере, можно увидеть в разделе «Храню» у меня на сайте.