Каскадные Таблицы Стилей

индекс
323,95

Фиксим png в IE6 с помощью expression, одним классом и без использования однопиксельного gif'а

Это давно известная проблема. У этой проблемы существуют 1000 решений, правда все они используют в конечном счёте один и тот же, проверенный AlphaImageLoader. Я, скорее всего, не открою Америку, а лишь хочу рассказать вам об expression'е, которым с недавних пор пользуюсь и которого достаточно в 99% случаев, а также объясню как, почему и зачем я его написал.


Началось всё с того, что когда я пришёл на новую работу, то узнал, что моим старым добрым прописыванием png-шек в свойстве filter фиксить png-ки нельзя: это раздувает код, от этого нужно избавляться, а самое главное что появляется неразбериха с путями в CMS'ке. К тому времени я уже привык, что background-repeat и background-position одним магическим взмахом руки не добиться в IE6, но как-то слишком много гемора была даже с простым фиксом картинок (к слову, моё решение проблем с указанными свойствами не решает!). Тогда мне пришлось воспользоваться тем решением, что использовали другие: jquery.iFixPng + отдельный js, когда нужно сделать sizingMethod=«scaled» и два класса для элементов «png» и «png-scaled». По началу я тоже использовал этот метод, но меня очень напрягало, что это всё-таки было чисто на JS. Я стал думать.

Написать решение на expression'ах не составило труда. Главное что нужно было сделать — это передавать внутрь экспрешена переменную z_gif — путь к однопиксельному прозрачному gif'у для фикса img-элементов. Но тогда я ещё не мог объяснить другим верстальщикам, почему способ на эскпрешенах лучше, чем на JS. Через какое-то время я стал работать над проектом, где на одной странице могло быть сразу где-то 20 png-шек. Именно тогда фикс на JS показал себя во всей красе, т.к некоторые картинки были размерами с полстраницы, то после загрузки сайта пользователь (в том числе и заказчики) секунды три видели непофикшенные картинки, и только потом всё становилось хорошо и красиво. Заказчики очень жаловались на это, а я пожимал плечами «ничего не могу сделать». А потом всё-таки решил попробовать заменить js-фикс на expression и добился желаемого: после загрузки пользователь не видел непофикшенных картинок, на их месте была пустота!

Универсальный класс


Я пользовался этим фиксом некоторое время, но меня не устраивало то, что для scaled картинок приходилось использовать отдельный класс. Я захотел исправить это и избавиться от двух классов (png и png-scaled) в пользу одного. Подумав я заметил, что в общем-то scale'ить нелогично картинки, у которых обе стороны больше 1 пикселя (понятно, что на 99% случаев найдётся 1, но меня устраивали 99), и я в expression'е написал условие, которое это проверяло и соответственно меняло sizingMethod на «scale»:

* html .g-png24 {
 behaviour:expression(
  !this.fixedPNG?
   (function(el){
    if (el.tagName.toLowerCase() == "img") {
     el.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + el.src + ")";
     el.style.backgroundImage = "none";
     el.src = z_gif; // А вот этот вот z_gif как раз и передаётся из html'ки, как-то так: <script>var z_gif = {{path-to-z-gif}}</script>
     }
     else {
      var sizingMethod = "crop";
      var tmpImg = new Image();
      tmpImg.src = el.currentStyle.backgroundImage.split('\"')[1];
      if (parseInt(tmpImg.width) == 1 || parseInt(tmpImg.height) == 1 || el.className.indexOf('g-png-24__scaled') > -1) {
       sizingMethod = "scale";
      }
     el.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + el.currentStyle.backgroundImage.split('\"')[1] + ", sizingMethod='"+sizingMethod+"')";
     el.style.backgroundImage = "none";
     el.src = z_gif;
    }
   el.fixedPNG = true;
   })(this):''
  );
 }


Вредный !important


Это решение работало у меня до случая, когда я применил фикс к элементу, у которого background-image был задан с флагом !important и фикс не сработал! Что ещё интереснее, другие фиксы также не работали! Я стал думать и перепробовав кучу вариантов: достучаться до !important флага с помощью JS, пересоздать новый элемент, клонируя все свойства, кроме background-image, достучаться до свойств currentStyle и иже с ними… А в итоге всё оказалось как-то слишком просто: в том же файле стилей нужно было создать дополнительное правило:

* html .png-fixed {
 background-image: none !important;
 }

и просто добавить элементу класс png-fixed и всё работало! :)

Ошибаться нужно?


Но и это решение не давало покоя. Меня не устраивала необходимость каждый раз передавать в expression путь к однопиксельному прозрачному gif'у и где-то я подозревал, что от него можно избавиться. Я вертел expression и так и эдак, параллельно оптимизируя код. Для начала я попробовал не задавать src, но вредный IE показывал над пофикшенной картинкой иконку незагруженной картинки. Облазил тонны сайтов со все возможными фиксами. Пытался вынести код в отдельную htc-шку. А потом я зачем-то задал картинке ширину и высоту в 1 пиксель и в итоге непофикшенная картинка стала 1х1, а пофикшенная отобразилась нормально рядом с ней. Я не поверил и стал дальше думать, как убрать эту 1х1 и задал src="" и её не стало. Я ликовал, моей радости не было предела, у меня что-то получилось… и когда я стал применять фикс, то… картинки перестали scale'ться. В попыхах я скопировал забыл вписать в код смену sizingMethod'а, а когда дописал его, фикс перестал работать.

Я думал это провал, потому что тогда я уже рассказал всем о своём красивом фиксе, для которого требовался только один файлик, но подумав почему у меня всё-таки что-то работало я вспомнил, что у sizingMethod возможных значений не 2, а 3, есть ещё и такое свойство «image»! В документации по этому значению написано что оно раздвигает или сжимает границы контейнера, чтобы вместить картинку. Но это оказалось не совсем так! Если элемент-контейнер меньше чем png, то png-шка покажется полностью, а элемент-контейнер останется в своих границах и именно это у меня и происходило, когда я задавал ширину и высоту = 1, а src="".

Итак, вот код моего фикса:

* html .g-png24 {
 behaviour:expression(
  (!this.fixedPNG?
   (function(el){
    var fixSrc = "", sizingMethod = "crop";
    if (el.tagName.toLowerCase() == "img") {
     fixSrc = el.src;
     sizingMethod = "image";

     el.style.width = 1;
     el.style.height = 1;
     el.src = "";
    }
    else {
     var tmpImg = new Image();
     tmpImg.src = el.currentStyle.backgroundImage.split('\"')[1];
     if (parseInt(tmpImg.width) == 1 || parseInt(tmpImg.height) == 1 || el.className.indexOf('g-png-24__scaled') > -1) {
      sizingMethod = "scale";
     }

     fixSrc = el.currentStyle.backgroundImage.split('\"')[1];
     el.className += " g-png-fixed";
    }
    el.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + fixSrc + ", sizingMethod='" + sizingMethod + "')";
    el.fixedPNG = true;
   })(this):'')
  );
 }

* html .g-png-fixed {
 background-image: none !important;
}


Конечно, хозяин-барин, и это решение спасает жизнь только в 99% случаев (и то, это мои 99% случаев, а у вас всё может быть совсем иначе) и значительно облегчает жизнь в принципе, потому что нужно всего-то подчключить файл с фиксом и задать нужным элементам класс «g-png24», вне зависимости img это или div! Кому-то возможно интереснее покажется решение Виталия Харисова (правда в нём он использует один доп.элемент-обёртку для img), или известный всем iePngFix.
+5
2 ноября 2009, 19:14
33

комментарии (50)

0
homm #
Знаете, очень интересно было читать, правда. Но должен вас огорчить, в IE8 больше нет expression, в png-шки фиксить по прежнему нужно. Простите.
0
Olegbl4 #
Странно, ни разу этого не делал. Можете пример выслать, когда нужно фиксить png в IE8?
0
homm #
Пожалуйста.
(нубы не в курсе, минусуют).
+2
Fesor #
Ну такое в верстке использовать попросту глупо.
0
Olegbl4 #
Почему же? А плавное проявление изображения? (fadeIn) Там хоть и в конце всё будет нормально, но промежуточные картинки не порадуют.
–1
Fesor #
0
nobr #
Хм… commons.wikimedia.org/wiki/File:PNG_transparency_demonstration_1.png — Всё ок.
0
homm #
А выше я привел ссылку, там не ОК. Вот такой вот парадокс.
0
nobr #
Может быть потому, что filter: alpha(opacity=50); — это не пнг-шка, а фильтр?
–1
homm #
Это — png-шка.
0
nobr #
…которая отлично отображается ;)

Да, я немного не прав оказался. Но ваш случай, согласитесь, довольно редкий, когда нужно динамически менять прозрачность полупрозрачной картинки. Я вижу применение только в тенях для модальных или всплывающих окон. Тут, конечно, нужно выкручиваться.
0
homm #
Но ваш случай, согласитесь, довольно редкий
Настолько редкий, что в каждом втором макете встречается. (не вру).
0
Fesor #
Ну а если бы все браузеры одинаково отображали все и поддерживали все одинакого, то какая б была прелесть в верстке то?)
0
aubt #
Откройте код — проблема есть когда на PNG с прозрачностью накладывается фиьлтр opacity, тоже с этим сталкивался.
0
homm #
Капитан пришел!
0
Olegbl4 #
Ну, так вы ещё и полупрозрачно. Я то говорю про хотя бы нормальное отображение png'шек, хоть с этим более-менее стало сладко, а вы хотите совсем рай.
0
homm #
Т.е. указанную проблему вашего способа вы игнорируете по причине, что она «совсем рай». А можно как-то в более понятных терминах?
0
Olegbl4 #
В указанном вами примере проблема возникает из-за применения свойства opacity к элементу с png картинкой. Если убрать opacity то картинка будет показана нормально. А в IE6 без применения фиксов (читай без опредённой магии и шаманства) png с альфа каналом будет показана на серой подложке. Неужели для вас это открытие?
0
homm #
Конечно нет. Может быть вы до сих пор не поняли. От указанной мной проблемы помогает точно тот-же фикс через AlphaImageLoader (неужели вы этого не знали?), а в вашем варианте фикса, он не может применен в ие8 для решения описанных мной проблем.
0
Olegbl4 #
А я заявлял поддержку ИЕ8?
+3
homm #
Ну это как-бы не логично, не поддерживать более старшую версию. Но бог с вами, не хотите, как хотите, я только предупредил, что в ряде случаев, где обычные фиксы полезны, ваш бесполезен.
+1
Olegbl4 #
Видимо я пока не так близко сталкивался с такими случаями, но спасибо за наводку, возьму на вооружение!
0
YuriPikin #
Спасибо за инфу, не знал
+6
DanStrogiy #
Нет смысла продолжать поддерживать IE6.
0
Olegbl4 #
Почему? =)
НЛО прилетело и опубликовало эту надпись здесь
0
Olegbl4 #
Каким это образом меня, как разработчика сайтов, касаются проблемы безопасности браузера? Они касаются юзера его использующего.
НЛО прилетело и опубликовало эту надпись здесь
+2
Olegbl4 #
Человек, ты статистику смотришь, матчасть учишь? Кто использует ИЕ6? Это большей частью офисные тётеньки и дяденьки, которые:
а. Не имеют возможности что-то изменить
б. Не знают как сделать.

Конечно, если ты делаешь сайт для себя, для друга, для тусовки, то можешь вообще поддерживать только один Сафари или Konqueror и всё будет зашибись. Если ты работаешь в компании, которая делает сайты, то просто плюнуть и сказать «под ИЕ6 не делаем» тебе НЕ ДАДУТ!
НЛО прилетело и опубликовало эту надпись здесь
+1
Olegbl4 #
Я рад за тебя, что ты можешь так легко принимать такие решения. А у нас заказчик, платит компании в которой я работаю семизначные суммы и просит, чтобы сайт у них отображался корректно и так же красиво, как было на макетах. Что будешь делать?
0
nobr #
Переводиться в вашу компанию :) Я даже ИЕ6 буду поддерживать за семизначные суммы :))
+1
Olegbl4 #
Пример был чисто гипотетический. ИЕ6 пользуются 15% пользователей рунета, среди них есть и наши заказчики, и наши потенциальные заказчики и глупо будет потерять заказ на миллион только потому, что по-вашему пользователь глуп и сидит под старым браузером, несмотря на то, что готов платить дохрена!
0
homm #
Еще некруглые уголки и многое другое можно делать с помощью восьмибитных полупрозрачных png-шек. Ие6 не рисует у них серой подложки, просто считает все полупрозрачные пиксели полностью прозрачными. Необходимость в дублировании файлов и кондишн комментах отпадает. Пример.
0
YuriPikin #
«Может, может… Но не звонит...» ©

Согласитесь, обновление firefox и ie — чертовски неравнозначные задачи для рядового юзера.
+2
TuiKiken #
Зависит от аудитории сайта. Если это молодёжный портал, то можно обойтись предупреждением сменить браузер, но если это портал домохозяек, то поддержка ИЕ6 на мой взгляд обязательна.

ПС: Недавно на работу позвонил клиент и сказал что в его браузере сайт не корректно работает. Оказалось он использует IE5… Вот даже так бывает.
+1
YuriPikin #
Как поступили? )
+1
TuiKiken #
Дальше я уже не следил за развитием событий, закинулся наушниками и продолжил работать. Но думаю верстальщику пришлось править =)
0
zona7o #
была похожая ситуация — продиктовали по телефону как обновить браузер.
+1
Narlie #
Как показывает практика на полпути стабилизации верстки под ие6 сайт становится ие5.5 валидным =) Не раз такое было.
0
catdog #
некрофилия это плохо.
–1
Narlie #
Взываю! Давайте дадим шестому умереть

п.с. хотя способ имеет право на жизнь
0
lashtal #
А оно для background-image на дивах работает, или по прежнему, поддерживается только img?
0
Olegbl4 #
Да, здесь распознаётся img тег отдельно. (я вот сейчас подумал, что ещё же есть input type=«image», возможно правильнее проверять на наличие scr)
–1
JN0iZzze #
Я думал по поводу IE6 топики уже перестали появляться…
–2
archimed7592 #
Да сколько ж можно png в IE6 фиксить? В течении пары лет встречаю на хабре топики «как пофиксить png в IE6»… Вам что, писать больше не о чем?
0
johnbl4ck #
нет, не все фиксы через AlphaImageLoader. Есть еще замечательный отличный DD_belatedPNG. Граблей с ним значительно меньше чем с другими вариантами, имхо.
0
Methos #
А ещё есть вариант, чтобы делать для 6-го осла прозрачные GIF. Тогда будет поддерживаться и background-position и repeat.

Для большинства случаев это работает хорошо, 24-битные картинки встречаются не очень часто, просто в этом случае в 6-ом осле будет не очень красиво — будет больше контраста (-:

Поэтому нужно ставить предупреждение, если браузер старый — обновите ваш браузер, он не поддерживает наши красивости, вот вам ссылка и приходите снова — и у вас всё будет красиво…

0
anmiles #
Ребята, экспрешены — это гениально, что бы ни говорили. Посудите сами: чем интенсивнее и дружнее мы их будем использовать, тем быстрее IE6 будет терять пользователей, окончательно разгневанных на тормоза :). И тем скорее мы потеряем всякую необходимость пользоваться экспрешенами и говнохаками вообще.
0
mitasovr #
Вот только имейте ввиду что экспрешн пересчитывается на каждое движение мышкой, на каждый фрейм каждой анимированной гифки и вообще на любой пук пользователя или страницы. Когда как свойство filter рендрится единождя при назначении стиля.

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