Это давно известная проблема. У этой проблемы существуют 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»:
Это решение работало у меня до случая, когда я применил фикс к элементу, у которого background-image был задан с флагом !important и фикс не сработал! Что ещё интереснее, другие фиксы также не работали! Я стал думать и перепробовав кучу вариантов: достучаться до !important флага с помощью JS, пересоздать новый элемент, клонируя все свойства, кроме background-image, достучаться до свойств currentStyle и иже с ними… А в итоге всё оказалось как-то слишком просто: в том же файле стилей нужно было создать дополнительное правило:
и просто добавить элементу класс png-fixed и всё работало! :)
Но и это решение не давало покоя. Меня не устраивала необходимость каждый раз передавать в expression путь к однопиксельному прозрачному gif'у и где-то я подозревал, что от него можно избавиться. Я вертел expression и так и эдак, параллельно оптимизируя код. Для начала я попробовал не задавать src, но вредный IE показывал над пофикшенной картинкой иконку незагруженной картинки. Облазил тонны сайтов со все возможными фиксами. Пытался вынести код в отдельную htc-шку. А потом я зачем-то задал картинке ширину и высоту в 1 пиксель и в итоге непофикшенная картинка стала 1х1, а пофикшенная отобразилась нормально рядом с ней. Я не поверил и стал дальше думать, как убрать эту 1х1 и задал src="" и её не стало. Я ликовал, моей радости не было предела, у меня что-то получилось… и когда я стал применять фикс, то… картинки перестали scale'ться. В попыхах я скопировал забыл вписать в код смену sizingMethod'а, а когда дописал его, фикс перестал работать.
Я думал это провал, потому что тогда я уже рассказал всем о своём красивом фиксе, для которого требовался только один файлик, но подумав почему у меня всё-таки что-то работало я вспомнил, что у sizingMethod возможных значений не 2, а 3, есть ещё и такое свойство «image»! В документации по этому значению написано что оно раздвигает или сжимает границы контейнера, чтобы вместить картинку. Но это оказалось не совсем так! Если элемент-контейнер меньше чем png, то png-шка покажется полностью, а элемент-контейнер останется в своих границах и именно это у меня и происходило, когда я задавал ширину и высоту = 1, а src="".
Итак, вот код моего фикса:
Конечно, хозяин-барин, и это решение спасает жизнь только в 99% случаев (и то, это мои 99% случаев, а у вас всё может быть совсем иначе) и значительно облегчает жизнь в принципе, потому что нужно всего-то подчключить файл с фиксом и задать нужным элементам класс «g-png24», вне зависимости img это или div! Кому-то возможно интереснее покажется решение Виталия Харисова (правда в нём он использует один доп.элемент-обёртку для img), или известный всем iePngFix.
Началось всё с того, что когда я пришёл на новую работу, то узнал, что моим старым добрым прописыванием 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.