Пользователь
0,0
рейтинг
12 апреля 2010 в 20:39

Разработка → К вопросу о кроссбраузерных Data URI

В погоне за оптимизацией сайтов захотел уменьшить количество запросов, не в ущерб размерам оптимизированных файлов.
Цель — передавать в одном файле изображения разных форматов, с разными настройками оптимизации.
Как средство, выбрал data uri и gzip'нутый css файл. Однако IE с data uri работают из рук вон плохо. Но в них есть mhtml. Существовавшая реализация не отвечала моим требованиям, т.к. приходилось 1 файл передавать два раза — раз для IE, в mhtml, и второй для всех остальных, в data uri. В поисках решения наткнулся на статью bolk'а, где описывалось решение для формата jpeg и некоторые теоретические выкладки для gif и png. После почти трехнедельного раскуривания манов мне удалось реализовать решение для gif и png и автоматизировать процесс для всех трех форматов.

BASE64


Поскольку изображения передаются в base64, стоит осветить некоторые, связанные с этой кодировкой, моменты
  • Во первых: base64 понимает только [A-Za-z0-9+/].
    При дешифровке браузерами или ruby либой все прочее символы дропаются.
    Консольный base64 на линуксе их не дропает и выводит ошибку.
  • Во вторых: base64 конвертит каждые 3 исходных байта (в нашем случае, ASCII символы) в 4 ASCII символа.
    Поэтому декодированную CSS строку надо уравновешивать, к примеру, нулями, что бы она правильно себя вела внутри закодированного файла.


Информация к размышлению:
Base64 в англоязычной викепедии



JPEG


Формат секций в JPEG:[заголовок][data]

C jpeg все просто и описано у bolk'а:
Открываем HEX-редактор:
FF D8 — заголовок JPEG для IE
FF E0 — объявление секции APP0, куда прячется всё до данных изображения,
«;background-color:url(data:image/jpeg;base64,» — это видят остальные браузеры.
      Когда IE декодирует эту строку, то получается хлам, который ни на что не влияет
FF D8 — начало JPEG для остальных браузеров
«данные изображения» — это место видят уже все браузеры


Смысл в том, что бы строка в CSS выглядела как:



И дешифровалась в IE как:



А другие ее видели как:



Из-за особенностей base64 надо дополнительно передавать некоторое кол-во символов, что бы строка шифровалась\дешифровалась верно. Они вставляются до и после CSS. Количество просчитывалось и подбиралось опытным путем:
/9j/4AA0;background-image:url(data:image/jpeg;base64;00,

Мой скрипт, который это процесс автоматизирует:
#!/usr/bin/ruby
require 'base64'
# тут строка ВСЕГДА равна одному значению:
a="/9j/4AA0;background-image:url(data:image/jpeg;base64;00,"

#Основной файл
b=Base64.encode64(File.open("#{ARGV[0]}",'r'){|f| f.read})

# Запись в файл
File.open('temp','w'){|i| i.write("#{Base64.decode64(a)}#{Base64.decode64(b)}")}

# перегонка файла обратно в base64
#cat test | base64 | tr -d "\n" > jpeg64.txt
File.open('temp2','w'){|o| o.write(Base64.encode64(File.open('temp','r'){|f| f.read}))}
#File.delete('temp')

c=File.open('temp2','r'){|f| f.read}.gsub(/\/9j\/4AA0backgroundimageurldataimage\/jpegbase6400/,"/9j/4AA0;background-image:url(data:image/jpeg;base64;00,").gsub(/\n/,"")

File.open('out_jpeg64','w'){|s| s.write("#{c}\);")}
File.delete('temp2')
# можно вставлять в css
# cat output64 | tr -d "\n"
# и хорошо поверить mhtml!!!


* This source code was highlighted with Source Code Highlighter.


Информация к размышлению:
JPEG в англоязычной викепедии



GIF


С этим форматом дела обстоят не так хорошо.
  • Во первых, размер его секции задает 1 байт, т.е. максимальная длина секции ff или 255 символов.
  • Во вторых: размер секции Comments почему-то ограничен размером в 240 байт, и 30 символов занимает CSS строка и еще несколько надо для 'уравновешивания' base64.
  • В третьих: Есть всего 2 блока, куда можно запихнуть 'мусор' — Application Extension и Comment Extension и они не могут идти перед General Color table. А таблица цветов может занимать максимум 256*3=768 байт.

Что можно сделать:
  • Не трогать General Color Table, если кол-во цветов не превышает ~70
  • Переместить содержимое General Color Table в Local Color Table


Я выбрал второй вариант, это делает base64 строку более читаемой и позволяет конвертировать любые не анимированные gif.

Более менее стандартный вариант секций GIF: [заголовок][размер][data][00]

Многие GIF имеют не совсем корректный порядок полей. Например если сделать `convert jpeg gif` то полученный файл адекватно обрабатываться скриптом не будет. Юзайте GIMP.
Первые 13 байт это та инфа, сокращать которую нельзя. Причем 11 байт является сложно-составным и описывает Global Color Table. Его меняем на 00
Вырезаем таблицу цветов (от 14 байта и до камента — 21 FE xx, где xx — размер коммента)
Коммент с css и первыми 13ю байтами.
Вырезаем таблицу цветов (от 14 байта и до камента — 21 FE xx, где xx — размер коммента)
'Внутренний кoммент' длиной в 1 символ
Вырезаем таблицу цветов (от 14 байта и до камента — 21 FE xx, где xx — размер коммента)
2c 00 00 00 00 — Image descriptor. Его 10й байт является сложно-составным и описывает Local Color Table. Переносим из 11-го байта все что переносится (объявить Local Color Table, сортирована\нет, размер Local color table), подробнее в спецификации формата.
Вставляем таблицу цветов
Продолжение Image descriptor


Смысл в том, что бы строка в CSS выглядела как:



При том что до всех правок файл выглядел как:



Мой скрипт для автоматизации процесса:
#!/usr/bin/ruby
# CONVERT INCORRECTLY TRANSFER DATA. USE GIMP INSTEAD
# USE: ./GIF_SCRIPT.RB [GIF_FILE]
require 'base64'

# OPEN GIF FILE IN HEX
orig=File.open("#{ARGV[0]}",'r'){|f| f.read.unpack("H*")}.to_s

# FUTURE HEADER
header=orig[0..25]

# GREP GENERAL COLOR TABLE
# [26..1565]/6 = 256 BYTE (MAX SIZE OF COLOR TABLE)
color_table=orig[26..1565][/(.*)21fe/,1]
if color_table.class == NilClass
  color_table=orig[26..1575][/(.*?)2c0000/,1]
end

# FOR DEBUGING
#puts color_table
#puts color_table.length
puts "COLORS IN PALLETE: #{color_table.length/6}"

# GIF IMAGE DATA
data=orig[/2c0000.*/]

# SAVE 11 BYTE'S INFO AND ADOPT IT FOR LOCAL COLOR TABLE
eleven=header[20..21].to_i(16).to_s(2)
local_mix="10#{eleven.split("")[4].to_s}00#{eleven.split("")[5..7].to_s}".to_i(2).to_s(16)

# 11 BYTE TO ZERO
header[20..21]="00"
# DECLARE LOCAL COLOR TABLE
data[18..19]=local_mix

# MAGIC COMMENT
comment=Base64.decode64(";background-image:url(data:image/gif;base64;pzd,").unpack("H*").to_s

# WRITE ALL IN ONE FILE
var=header+"21fe313030"+comment+header+"21fe013000"+data[0..19]+color_table+data[20..-1]
File.open('
out.gif','w'){|f| f.write(var.to_a.pack("H*"))}

# ENCODE FILE TO BASE64 WITH "\n" REMOVING
File.open('
temp','w'){|o| o.write(Base64.encode64(File.open('out.gif','r'){|f| f.read}).gsub(/\n/,""))}

# MAKE STRING CSS READEABLE
c=File.open('
temp','r'){|f| f.read}.gsub(/backgroundimageurldataimage\/gifbase64pzd/,";background-image:url(data:image/gif;base64;pzd,").gsub(/\n/,"")
File.delete('
temp')

# JUST PASTE TEXT FROM THIS FILE TO CSS
File.open('
out_gif64','w'){|s| s.write("#{c}\);")}


* This source code was highlighted with Source Code Highlighter.



Для анимированного гифа скрипта нет. Я считаю что лучше использовать анимированными CSS sprites.

Теоретические выкладки:
  • Для каждого кадра делать Local Color Table смысла не имеет, т.к. это увеличит размер.
  • Анимированные гифы с кол-вом цветов 64 могут обрабатываться с включением General Color Table в коммент
  • Application Extension и Comment Extension могут идти подряд, что увеличивает возможный размер x2.
  • На просторах интернета я встретил информацию о том, что в Application Extension фактически 2 блока задают размер.
    21 ff SizeSize 'NETSCAPE2.0' SizeSize 01 00 00, где SizeSize — 2 байта отвечающие за размер, а 01 байт отвечающий за infinitive loop.
  • Что, в теории, может предоставить возможность 'забить' большее кол-во цветов. Но все-равно меньше 256 (около 230).



Информация к размышлению:
GIF color tables
Gif specification



PNG


После gif это тихая гавань. У секций размер не ограничен, у них 4байтные заголовки и их очень удобно искать. Для сравнения, для gif я ломал голову и дебажил скрипт почти весь день, а для png все сделал за час.

Формат секций в PNG: [размер(4 байта)][data][CRC(4 байта)]

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

Многие PNG имеют не совсем верную структуру, во всяком случае, мой скрипт с нми работать не будет, пока не прогнать их через optipng. Помимо оптимизации изображения, эта прога выставит поля в нужном порядке. Также, мною замечено что Photoshop иногда режет поля sRGB и им сохраненные png обрабатываются не всегда.

CSS будем прятать в секции tEXt

PNG надо сразу заоптимизировать с помощью optipng, потом нарезать таким образом, что бы tExt был сразу за IHDR.
В секции tEXt обязательно должен передаваться keyword00, его длина учитывается в общей длине секции. У меня это 'Comment '

Общий порядок:
IHDR
tExt
Другая служебная информация
data



Было:



Стало:



Скрипт хорошо комментирован, и в спецификации тоже можно многое почерпнуть

IE6 не видит прозрачности, иногда это можно исправить с помощью bKGD выставляя нужный Background color.

После чего запускаем `optipng -fix FILE` что бы исправить CRC секции tEXt

Мой скрипт для автоматизации процесса:
#!/usr/bin/ruby
#
#!!!! RUN optipng FIRST !!!!
#
# USE: ./PNG_SCRIPT.RB [PNG_FILE]
require 'base64'
# OPEN GIF FILE IN HEX
orig=File.open("#{ARGV[0]}",'r'){|f| f.read.unpack("H*")}.to_s

#ihdr=orig[0..65]
ihdr=orig[/(.*?)73524742/,1][0..-9]

#sRGB - 73 52 47 42 & -4b (8 characters)
#srgb_phys=orig[66..171]
#check for tEXt existence
if orig[/74455874/].class == NilClass
  srgb_phys=orig[/(.{8}73524742.*?)49444154/,1][0..-9]
else
  srgb_phys=orig[/(.{8}73524742.*?)74455874/,1][0..-9]
end

#srgb_phys=orig[/(.{8}73524742.*?)74455874/,1][0..-9]

#tEXt - 74 45 58 74 –њ–Њ—Б–ї–µ–і–љ–Є–µ 8 –љ–∞–і–Њ –Љ–µ–љ—П—В—М –љ–∞ CRC 00000000
#text=orig[172..245]
#text=orig[/(.{8}74455874.*?)49444154/,1][0..-9]

#IDAT - 49444154
#data=orig[246..-1]
data=orig[/.{8}49444154.*/]

#MAGIC COMMENT
comment=Base64.decode64(";background-image:url(data:image/png;base64;pzd,").unpack("H*").to_s

###### OUTER PNG
# "00000059"+"74455874"+"436f6d6d656e7400"
# tEXt_length + 'tEXt' + 'Comment.'
# "3030" - two zero for base64 balance
###### INNER PNG
# "00000008"+"74455874"+"436f6d6d656e7400"+"00000000"
# min_tEXt_length + 'tEXt' + 'Comment.' + blank CRC
#
# CRC field one for two PNG's
# IE can'
t live without it, but others feel indifferently
var=ihdr+"00000059"+"74455874"+"436f6d6d656e7400"+"3030"+comment+ihdr+"00000008"+"74455874"+"436f6d6d656e7400"+"00000000"+srgb_phys+data

File.open('out.png','w'){|f| f.write(var.to_a.pack("H*"))}

# CRC FIX
puts "optipng -fix started..."
`optipng -fix out.png`
puts "optipng -fix completed"

# ENCODE FILE TO BASE64 WITH "\n" REMOVING
File.open('temp','w'){|o| o.write(Base64.encode64(File.open('out.png','r'){|f| f.read}).gsub(/\n/,""))}

# MAKE STRING CSS READEABLE
c=File.open('temp','r'){|f| f.read}.gsub(/backgroundimageurldataimage\/pngbase64pzd/,";background-image:url(data:image/png;base64;pzd,").gsub(/\n/,"")
File.delete('temp')

# JUST PASTE TEXT FROM THIS FILE TO CSS
File.open('out_png64','w'){|s| s.write("#{c}\);")}


* This source code was highlighted with Source Code Highlighter.


Информация к размышлению:
PNG Basics
PNG Specification



MHTML


Если используется MHTML то CSS должен быть весь отредактирован под него и разбит на секции(пример в архиве):
/*
Content-Type: multipart/related; boundary="_"

--_
Content-Type: text/css;

*/
html, body {
 margin: 0;
 padding: 0;
 width: 100%;
 height: 100%;
}

#half_logo {
/*
--_
Content-Location:logo
Content-Transfer-Encoding:base64
Content-Type: image/png;*/

iVBORw0KGgoAAAANSUhEUgAAAT4AAAA3CAMAAACintZ+AAAAWXRFWHRDb21tZW50ADAw;background-image:url(data:image/png;base64;pzd,iVBORw0K...);

/*
--_
Content-Type: text/css;

*/
background-image: url(mhtml:http://192.168.1.2/test.css!logo) !ie;
/*
--_--
*/

* This source code was highlighted with Source Code Highlighter.


Архив с исходниками и скриптами
Пример рабочего сайта

Тестировалось в FF 3.6, Opera 10.10, chromium, chrome, IE6-8

P.S: Автором этой статьи является мой хорший друг Banderlog. Статью размещаю по его просьбе, соответственно вопросы рекомендую задавать ему напрямую в jabber: banderlog@jabber.com.ua
P.P.S: Странно что только на второй день обнаружился тот факт что при посте статьи была допущена ацкая ошибка в скриптах. Все 3 были одинаковыми.
Чиркин Дима @josser
карма
47,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (87)

  • +4
    если CRC битый то IE не будет отображать картинку
    ну хоть в чём-то…
    • +5
      Web плавно переходит на асм
  • +3
    Если сделаете онлайн сервис для конвертации — цены вам не будет :)
  • 0
    Честно говоря, не знаком с этой технологией и из описания не понял существенных плюсов и технологии применения.
    Поясните как для чайника, в чем плюс в отличии от обычных изображений и в чем заключается технология, в обработке каждой закачиваемой картинки?
    • +1
      Один http запрос за большим css файлом с внедренными картинками, нежели много запросов за кучей мелких картинок.
      • 0
        а не проще все изображения (в особенности одного размера) поместить в одну картинку-полоску и через css обращаться к какждой картинки из этой полоски (забыл как это называется)?
        • 0
          спрайты называется, вопрос в автоматизации сбора такой картинки и пересбора при изменениях
        • +1
          Автор попросил передать Вам ответ:
          если все файлы забить в css sprite то невозможна тонкая оптимизация изображений, допустим по палитре
          • 0
            Так sprites обычно делается для мелких иконок, которые в общем-то, и 1 запрос к спрайту с оверхедом 5-10 Кб гораздо лучше 5-10 запросам по 512 байт.

            Вот реальная проблема — это сложности при переверстке, это да. + для Хромого надо еще в png8 все полупрозрачные картинки дублировать.
        • –3
          пока не загрузится вся картинка, будет ощущение что сайт не загрузился до конца, эффект пропадет
          почитайте на webo.in про это, или посты sunnybear
          • 0
            Контент-картинки надо грузить оттдельно (причём можно через lazy load). В CSS через DATA URI интегрировать только вёрстку. Пока она грузится, возможно, стóит затенить стреницу и вывести крутилку. IMHO.
      • 0
        > Один http запрос за большим css файлом с внедренными картинками, нежели много запросов за кучей мелких картинок.

        А пепревешивает ли выигрыш от этого ту проблему, что объём в Base64 больше чем исходный?
        • +1
          Base64 + Gzip ~ src
        • 0
          Предполагаю, что если статику отдает не nginx, то выигрыш от уменьшения числа соединений есть.
          Но я не эксперт, точно не знаю.

          Если речь о 20-30 картинках, то можно вообще не заморачиваться я думаю. Разница заметна на нескольких сотнях (богатые интерфейсы, онлайн приложения, игры).
    • 0
      вот вам статьи на тему duris.ru/articles/ с детальным обзором, зачем и почему.
  • 0
    > т.к. приходилось 1 файл передавать два раза — раз для IE, в mhtml, и второй для всех остальных, в data uri

    а почему передавать два раза? один раз для ИЕ, и один раз раз для всех остальных. если правильно подключать — совместная передача не происходит. Попробуйте duris.ru, там реализован механизм подключения только того что нужно.

    а вообще статья отлично расписывает возможности объединения файлов, думаю пригодится.
  • 0
    кстати, а может стоит разделить css файл на две части, отдельно css без data:uri и отдельно css mix data:uri + mhtml, тогда будет возможность прогнать первую часть через css компрессор да и не надо будет писать постоянно Content-Type: text/css;

    и было клево с PNG сделать без предварительного прогона через optipng.

    Спасибо за исследования! очень редко такие статьи стали появляться.
  • +2
    А как называется этот интересный шрифт у Вас на схемках?
    • 0
      DS Goose.ttf
  • +1
    В IE8 НЕ работает
    В IE7 работает
    • 0
      засада, подтверждаю в ИЕ8 не работает
      • +2
        Автор попросил ответить:
        файлы из архива и сайт по ссылке не отрабатывали в IE8 потому что хак, который я использовал в css работает только с <IE7. Сейчас на сайте включен режим эмуляции IE7 и все нормально отрабатывает. Для более изящного решения нужен другой css хак.

        img215.imageshack.us/img215/5381/201004122229181680x1050.png
        это пруфскрин
        • 0
          для ИЕ8 надо как-то указать чтобы работал как обычные нормальные браузеры, используя data:uri
      • +3
        И ещё чуть-чуть:
        можно и без дуриса, просто через .htaccess передавать файл с одним mhtml для ie и с datauri для всех остальных. сейчас для ie передается не gzip'нутый css, а для остальных gzip'нутый. Без optipng можно, но для этого поля в png файле должны быть выставленны в правильном порядке (в таком, в каком их понимает мой скрипт), а optipng это просто удобно. Но никто не мешает написать свой скрипт\улучшить сцществующий. Мои скрипты лишь пример реализации.
        • 0
          можно, хотя я думаю что оптимальнее эту логику на клиенте расположить. Скрипт однозначно стоит улучшить, при возможности портирую на Java.
        • 0
          Я сталкивался с проблемой использования mhtml для IE в win7, а так же слышал что он также не работает и в vista. Не слышали про такое?
          • 0
            Есть проблема в IE7 под Vista.
          • +1
            проблема была, но уже решена, смотрите ссылку в комментарии ниже
  • 0
    Хм… Технология, возможно, хороша, но намного ли это будет быстрей CSS спрайтов со внешней картинкой? Да, со спрайтами на один HTTP запрос больше, но стоит ли этот один запрос такого усложнения цикла разработки сервиса?

    Ведь на странице у вас в любом случае будут картинки помимо закодированных — фотографии, иллюстрации к статьям или портфолио и т.п. Да и на любом мало-мальски серьезном проекте всегда есть что усовершенствовать помимо data:URI.

    В общем, вопрос в чем: адекватны ли затрачиваемые усилия достигаемому результату?
    • 0
      вопрос в полной автоматизации создания data:uri css sprites, что не реализуемо на 100% при обычных спрайтах.
      • 0
        Вопрос адекватности — не только в автоматизации.

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

        На больших проектах это достаточно сильно может увеличить трудоемкость, даже если будет автоматизировано.

        Получится ли сопоставимый этому геморрою результат?
        • –1
          все это (как и спрайты) полностью автоматизируется. Не зря же WEBO Site SpeedUp уже год успешно работает :)
          • 0
            А разве можно автоматизировать создание спрайтов? Там же все может быть очень сложно сделано.
            • 0
              может быть, а может и не быть.
              Мы год назад эту задачу в 95% случаев решили. И только через полгода Steve Souders выкатил свой SpriteMe, который не все возможные случаи обсчитывает.
              • 0
                Ну не знаю, что-то сомневаюсь я, бывают же когда ширина/высота в стилях прописана не в пикселах (или вообще не прописана), background-position не в пикселях, бывает определения раскиданы по разным селекторам, бывает для ИЕ отдельные правила.

                А банальные определения типа height: 20px, width: 20px, backgound-position: 50% — это да, наверно автоматизируется.
                • 0
                  95% случаев автоматизируется. Даже с относительным background-position, даже без задания размеров, даже когда определения по разным селекторам раскиданы.
                • 0
                  зато с data:uri автоматизируются 100% :P
        • 0
          получится, нужно просто иметь нормальное автоматизировано средство от геморной боли
          в нормальной проекте все равно используется какой-то инструмент оптимизации. вызовом одного скрипта собирается весь оптимизированный билд.
          • 0
            В теории — да. Но на практике, как я понимаю, пока такого средства не только нет, но и сами даже выкладки существуют только в теории и никем серьезно на нормальном проекте не тестированы?
            • 0
              ошибаетесь — средство есть и в проектах нормальных используется, как примеры kinobaza.tv, ide.hivext.ru, www.dolcevilla.cz
              • 0
                интересно, каким образом duris к живому сайту прикручивался…
                • 0
                  с помощью offline версии, кстати сейчас режим тестирования проводим, если есть достойный проект — могу сделать билд под него

                  для этого необходимо написать письмо на адрес duris.ru[гав]gmail.com (ну или мне в личку) с пометкой в теме «duris offline». В письме укажите следующие данные:
                  — язык программирования
                  — кратко опишите прицип работы и структуру проекта
                  — ссылка на online сайт проекта

                  обычные домашние страницы не рассматриваются, на данный момент отрабатываем под проекты средней и выше средней сложностей.
                  • 0
                    спасибо!
                    будет сделано в скором времени!
    • 0
      намного. Просто поверьте :)
    • +2
      Ответ автора через моё посредничество:
      сия технология не всеобъемлюща и не идеальна. через нее стоит пропускать лишь те изображения, которые встречаются на каждой странице(или просто часто). После написания скриптов процесс внедрения занимает ОЧЕНЬ мало времени.
  • 0
    С swf случайно не эксперементировали в MHTML?

    Довелось поковыряться с внедрением swf для копирования текста со страницы в буфер обмена — flash-плагин не поддерживает data uri (на сайте Adobe было упоминание, что пока и не планируется добавление поддержки), а браузеры самостоятельно не преобразовуют данные перед передачей плагину, в итоге пришлось отказаться от этой затеи.
    • 0
      *экспериментировали

      К ночи пальцы путаются…
      • +1
        Автор попросил передать, что:
        • +1
          ой
          …что:
          нет, с swf не экспериментировал
  • +3
    Кстати, если кто-то хотел бы поделиться с автором статьи инвайтом — он был бы не против его получить. Пишите мне в личку, дам адрес электронной почты.
    • +3
      Ну или пишите по приведённому в конце статьи jabber-адресу: banderlog@jabber.com.ua.
      • +2
        спасибо тов. Artqookie, инвайт получен X)
        отдельная благодарность тов. dtf за согласие побыть некоторое время посредником :)
  • +1
    Мне кажется лучше не парится и отдавать ie6 и ie7 сами изображения:

    body{background:url(data:image/png;base64,blablabla)}
    * html body{background:url(../images/blablabla.png)}
    *:first-child + html body{background:url(../images/blablabla.png)}
    • +1
      * html {}
      *+html {}
      ^^^ смотрится элегантнее и меньше байтов :)
      • 0
        >> меньше байтов :)

        Тогда уж в первом случае можно без пробела после астериска:
        <tt>*html{}</tt>


        :)
        • 0
          *html{}

          Irony и всё остальное парсер режет, а tt оставляет и даже со скобками, странно.
    • 0
      обоснуйте
    • 0
      Полностью поддерживаю. Я тоже не заморачиваюсь с IE6 и 7 и отдаю им спрайт из изображений, а нормальным браузерам css-файл с dataURL изображениями.
  • 0
    Спасибо. Не знал раньше вообще что есть такая Data URI.

    Помимо указанного применения с интеграцией графики в CSS сразу вырисовываются такие применения:

    Написать сохранялку страниц, которая будет брать любую открытую в браузере страницу и давать на выходе один стандартный html-файл, внедряя внутрь него и CSS и JS и теперь ещё графику. Раньше такое уже было в MHT, но теперь есть возможность делать стандартный HTML.

    Внедрять картинки в почтовые и др. сообщения не ввиде ссылок и не ввиде приложений, а прямо так. Кстати интересно, у кого карма положительная и теги можно использовать, попробуйте-ка в теге IMG в комменте так картинку вставить?
    • 0
      Вот:

      • 0
        Не сработало. Парсер порубал содержимое атрибута src и вообще выкинул атрибуты width и height.
    • 0
      >> Раньше такое уже было в MHT, но теперь есть возможность делать стандартный HTML

      Есть пара небольших препятствий:

      1. В rfc говорится:
      «A new URL scheme, „data“, is defined. It allows inclusion of small data items...»
      насколько «небольшие» элементы — не оговаривается. К примеру, в MSIE максимальный размер — 32,768 символа. Т. е. могут быть проблемы с совместимостью, особенно если через data uri включены крупные файлы.

      2. И снова MSIE: «For security reasons, data URIs are restricted to downloaded resources. Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements.»
      Т.е. попросту — так можно внедрять только картинки, а скрипты и содержимое фреймов — не судьба.
      • 0
        Ну да, и еёщ одно:

        3. В rfc определяется следующий синтаксис:

        dataurl := «data:» [ mediatype ] [ ";base64" ] "," data

        Т.е. после данных не может идти ничего. Если вдруг понадобится передать параметры в data uri, то ничего не получится, т.е. конструкция вида:

        window.open('data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E...%0D%0A?param1=value1¶m2=value2','_blank','height=500,width=200');

        работать, к сожалению, не будет.
      • 0
        > максимальный размер — 32,768 символа

        В общем случае должно прекрасно хватить.

        > так можно внедрять только картинки, а скрипты и содержимое фреймов — не судьба.

        А зачем скрипты так внедрять когда можно внутри тега script открытым текстом?
        • +1
          > В общем случае должно прекрасно хватить.

          В общем случае — да (я потому и написал «небольших»), но если действительно сделать сохранение страниц в один файл, то могут быть проблемы с чтением сохранённого файла, если, к примеру, на странице присутсвуют большие картинки (проблемы скорее всего только в MSIE — проверю, отпишусь, самому интересно стало).

          > А зачем скрипты так внедрять когда можно внутри тега script открытым текстом?

          Не обязательно скрипты: содержимое iframe'ов, содержимое фреймов во frameset'е.
        • +1
          >> В общем случае должно прекрасно хватить.

          В общем — да, я поэтому и написал, что «небольшие», но если сохранять страницы со всем содержимым в один файл, он может получиться нечитабельным в MSIE, может ещё где-то… поэкспериментирую, отпишусь.

          >> А зачем скрипты так внедрять когда можно внутри тега script открытым текстом?

          Скрипты — ещё ладно, но с iframe'ами и фреймами frameset'а ничего не получится в ИЕ.

          Т.е. сохранять вполне можно, но для начала нужно эксперементально установить максимальный размер файлов для разных браузеров и при наличии файлов, превышающих данный предел, а также при наличии в документа iframe'ов и frame'ов выдавать предупреждение о возможной нечитабельности документа.
          • 0
            Вчера ответ отправился, но на странице не отображался даже после нескольких обновлений, теперь второй раз отправил — появился :(
        • +1
          Похоже, ограничение на длину data uri есть только в ИЕ: поэксперементировал, Opera, Firefox, Chrome нормально работают со ссылками длиной 500+, 1000+, 12000+ тыс. символов (т.е. 500 Кб, 1 Мб, 12 Мб).

          Использовал готовый Jpeg на 15 кб, в котором скриптом дописывал последовательсть символов в exif данные для увеличения размера файла, затем кодировал в base64 и отдавайл в браузер HTML с картинкой в data uri.

          12-мегабайтная длина ссылки data uri (со скрипом и тормозами, но открылось везде):
          Opera 10.5: i41.tinypic.com/2vxiwdz.png
          Chrome 4.1: i41.tinypic.com/r7kj9x.png
          Firefox 3.6: i39.tinypic.com/29kxmbc.jpg

          MSIE 8 ведёт себя следующим образом: если длина ссылки превышает упомянутый предел в 32768 символа, то «лишнее» просто обрезается и отображается часть данных, в данном случае, начальный кусок картинки:

          i42.tinypic.com/ilaka9.png
          • 0
            P.S. Упомянутая на скриншотах «Data URI length 12 019 971 bytes» соответствует размеру файла в 8.5 Мб (9 014 960 байт — увеличение размера произошло за счёт кодирования в base64 + дополнительные символы в начале ссылки 'data:image/jpeg;base64,').
          • 0
            Не знал, что IE8 просто обрежет все что не помещается в его максимальный размер data uri и все равно что-то отобразит.
            • 0
              Я тоже не знал, поначалу попробовал мегабайтную ссылку — ни отобразило ничего, потом вспомнил, что я увеличиваю файл за счёт увеличения длины exif данных, т.е. если данные обрезаются, показывать нечего.
              Поэтому попробовал что-то незначительно превышающее указанный на сайте MS предел — оказалось, не так всё и страшно :)
              • 0
                Мегабайтную ССЫЛКУ? Фигассе. Не дай бог такие в закладки добавлять… :)
                • 0
                  Она же ссылка только формально, на деле — файл помещённый в ссылку, т.е. не указатель на ресурс, а по сути сам ресурс. :)
  • 0
    Для MSIE надо отдавать отдельный файл без data:url, с нормальными путями к картинкам.
    • 0
      почему?
      • 0
        Чтобы не делать таких ненатуральных плясок с бубном.
        • 0
          а css с data:url разве натуральные пляски? у каждого разная степень мастерства в танце. тем более так танцевать может только один на тысячу. Дело в том, что потом смогут и остальных 999 так же танцевать, если этот один сделает автоматический передвигатор ног :). Постарался объяснить на пальцах… на пальцах ног.
          • +1
            спасибо Х) Только я никак не могу взять в толк, о каком дальнейшем автоматическом передвигаторе ног идет речь. На данный момент все максимально просто и удобно (по себе равняю, понятное дело) — натравил нужный скрипт на нужный файл, и вставил строчку в CSS.
  • +1
    Эм, а в чём проблема с условными комментариями?
  • +1
    Не знаю, заметили все или нет, но в статье ошибочно опубликовано 3 одинаковых скрипта, для 3х разных форматов. Исправлю как только свяжусь с josser.
    В архиве скрипты правильные
    • +1
      честно говоря так и не понял как дело обстоит с ИЕ8? под него надо отдельно генерить код картинки?
      • +1
        Не, на все случаи жизни генерируется 1 картинка, которая в base64 виде и вставляется в CSS.
        Далее: IE6-7 не понимают datauri и скипают их, но видят css-хак '!ie' и отрабатывают mhtml.

        IE8 понимает datauri до 32Kb, но не показывает их, ибо там битый CRC, а хак '!ie' он не понимает и строку с ним не отрабатывает.
        Посему надо использовать css-хак который понимают все IE, либо в HEAD html добавать:
        <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7 \>
        что заставит IE8 отработать как IE7 (в этом случае css-хак '!ie' сработает).

        Просто я осознал что мне неизвестен универсальный, красивый и короткий css-хак для всех версий IE.
        • 0
          >> IE8 понимает datauri до 32Kb, но не показывает их, ибо там битый CRC

          Немного поэксперементировал с размерами данных, отписался чуть выше.
  • 0
    UPD: Пример рабочего сайта перестал быть таковым.
    В своем текущем проекте я вообще отказался от поддержки <IE8 и мир стал, субъективно, чуточку лучше.
    Тема трансформировалась в чисто академическую.

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