Короткий способ определить есть ли поддержка dataURI

Придумал короткий способ определить поддержку data URI в браузере:
<script src="data:text/javascript,self.dataURI=1"></script>
Потом просто проверяете у window свойство dataURI, если оно есть, то есть и поддержка. Способ не работает в IE8 и IE9 — тот и другой не умеют загружать Джаваскрипт этим образом. Собственно, меня это не волнует — мне как раз и нужно определить, что Джаваскрипт так работает, но если вам нужно не это, то должен работать вот такой способ:
<link rel="stylesheet" href="data:text/css,html{font-size:99px}">
То есть устанавливаем у тега HTML какое-нибудь свойство, которое потом в BODY перекроем, а позже, чтобы убедиться, что поддержка дата-ури есть, смоторим что вышло (тут я при помощи jQuery это делаю):
/99/.test($('html').css('font')); // true, если есть поддержка dataURI

Кроссбраузерный data URI в CSS-файлах (подробно)

Кстати, всё забываю порекомендовать статью Banderlog'а, который написал её по мотивам моей статьи «Кроссбраузерный data URI в CSS-файлах», прекрасно разложив всё по полочкам и детально проработав тот же подход в форматах PNG и GIF.

Статья на Хабре называется «К вопросу о кроссбраузерных Data URI».
Комментировать
17 ноября 2010 20:33

Кроссбраузерный data URI в CSS-файлах (многабукв)

Прелюдия

Некоторое время назад, я нашёл способ, использования data URI в Internet Explorer. Data URI — специальный вид URL, который включает в себя код самого объекта. Например, таким образом можно внедрять изображения прямо в код HTML-страницы.

Выглядит такой 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 с пятой версии, в одном из экспериментов разобрался как внедрить объект в тело HTML-документа и, что важнее, придумал как совместить оба способа (data URI и MHTML) в одном документе.

Вообще mhtml был придумал для адресации внутри так называемых «веб-архивах» — формат, очень похожий на формат писем электронной почты и предназначенный для сохранения веб-страниц вместе с картинками, стилями, JavaScript и прочим в одном файле. Сейчас он, так или иначе, поддерживается большинством браузеров.

Типичный mhtml-адрес выглядит следующим образом:
mhtml:http://example.net/index.html!fhhryregdy4gere
Где после «mhtml» идёт обычный веб-адрес, а после восклицательного знака — идентификатор объекта внутри веб-архива. Как я уже сказал, веб-архив очень похож на почтовое сообщение, где один из методов кодирования объектов — base64, тот же самый, который применяется и в dataURI.

В итоге, когда мне пришла эта идея, я совместил оба способа так, чтобы Internet Explorer видел файл как веб-архив с закодированным base64 объектом, а остальные браузеры видели этот закодированный объект как часть dataURI.

Специфика HTML допускает переносы, в том числе и внутри data URI, поэтому мне удалось задуманное относительно быстро. В CSS всё сложнее, а тема использования data URI в CSS, как оказалось, актуальнее, чем для HTML. Например, в книге Николая Мациевского «Разгони свой сайт» сделана попытка расширения моего способа на CSS, к сожалению, менее удачная, чем хотелось бы: требуется включение закодированного объекта два раза.

Фуга

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

После немногочисленных экспериментов, оказалось, что оторвать закодированный объект от начала data URI не представляется возможным, что мешает использованить mhtml — там заголовок и кодированный объект должны отделяться пустой строкой.

Тем не менее, других способов побороть IE я не видел и потому продолжал эксперименты. Несколько слов о том, что такое base64. Base64, по сути, анахронизм, доставшийся нам от электронной почты на заре её зарождения. Письма тогда ходили исключительно в латинице и все почтовые системы полагали, что никаких других символов в письмах не бывает.

Таким образом, когда встала задача передавать в письмах что-то кроме англоязычных текстов (например, файлы или тексты на других языках), было придумано несколько способов кодирования таких объектов. Один из них — base64 (для математиков — это позиционная система счисления с основанием 64). 64 — это количество знаков, которая использует это кодирование. Это символы A-Z, a-z, 0-9 и плюс со слешем.

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

Итак, строка data URI начинается с чего-то вроде «data:image/gif;base64,» и в CSS не терпит переносов, а MHTML требует, чтобы кодированная строка начиналась с начала строки.

Из вышесказанного следует, что нужно как-то сделать начало 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-стиля для остальных браузеров не кодируется и IE декодирует её как мусор внутри APP0).

В моём примере такой CSS выглядит вот так:
/9j/4AAs;background-image:url(data:image/jpeg;base64;BOLKNOTE.RU,/9j/4AAC…
Легко увидеть, как видит этот стиль браузер: «/9j/4AAs» кажется ему ошибочным атрибутом (его, кстати, можно взять в комментарий), а «;» — разделителем атрибутов. И хорошо просматривается («/9j/AA») двойной старт заголовка JPEG-файла. IE начнёт декодирование с первого заголовка, другие браузеры — со второго.

Остальное должно быть понятно из примера («!ie» — CSS hack, делающий стиль видимым только для IE), как это выглядит в браузере, можно увидеть в разделе «Храню» у меня на сайте.
23 комментария
21 марта 2009 21:48