Фиксим 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.

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 50

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

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

                        Конечно, если ты делаешь сайт для себя, для друга, для тусовки, то можешь вообще поддерживать только один Сафари или Konqueror и всё будет зашибись. Если ты работаешь в компании, которая делает сайты, то просто плюнуть и сказать «под ИЕ6 не делаем» тебе НЕ ДАДУТ!
                        • UFO just landed and posted this here
                            +1
                            Я рад за тебя, что ты можешь так легко принимать такие решения. А у нас заказчик, платит компании в которой я работаю семизначные суммы и просит, чтобы сайт у них отображался корректно и так же красиво, как было на макетах. Что будешь делать?
                              0
                              Переводиться в вашу компанию :) Я даже ИЕ6 буду поддерживать за семизначные суммы :))
                                +1
                                Пример был чисто гипотетический. ИЕ6 пользуются 15% пользователей рунета, среди них есть и наши заказчики, и наши потенциальные заказчики и глупо будет потерять заказ на миллион только потому, что по-вашему пользователь глуп и сидит под старым браузером, несмотря на то, что готов платить дохрена!
                              0
                              Еще некруглые уголки и многое другое можно делать с помощью восьмибитных полупрозрачных png-шек. Ие6 не рисует у них серой подложки, просто считает все полупрозрачные пиксели полностью прозрачными. Необходимость в дублировании файлов и кондишн комментах отпадает. Пример.
                        0
                        «Может, может… Но не звонит...» ©

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

                      ПС: Недавно на работу позвонил клиент и сказал что в его браузере сайт не корректно работает. Оказалось он использует IE5… Вот даже так бывает.
                        +1
                        Как поступили? )
                          +1
                          Дальше я уже не следил за развитием событий, закинулся наушниками и продолжил работать. Но думаю верстальщику пришлось править =)
                            0
                            была похожая ситуация — продиктовали по телефону как обновить браузер.
                            +1
                            Как показывает практика на полпути стабилизации верстки под ие6 сайт становится ие5.5 валидным =) Не раз такое было.
                        • UFO just landed and posted this here
                            –1
                            Взываю! Давайте дадим шестому умереть

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

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

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

                                      • UFO just landed and posted this here
                                          0
                                          Вот только имейте ввиду что экспрешн пересчитывается на каждое движение мышкой, на каждый фрейм каждой анимированной гифки и вообще на любой пук пользователя или страницы. Когда как свойство filter рендрится единождя при назначении стиля.

                                          Only users with full accounts can post comments. Log in, please.