Pull to refresh

подводные камни анимации png в IE

Reading time 4 min
Views 2.4K
Все мы, здесь присутствующие, горячо любим IE6, чуть менее горячо — IE7 и искренне верим (правда, не все и не всегда признаёмся в этом) в IE8. Здесь писали про множество способов борьбы с особенностью шестого издания мелкомягкого браузера не понимать формат png. Но все эти обсуждения касались просто загрузки png-картинок. А передо мной возникла гораздо более интересная (и более сложная) задача — анимация этих картинок. И всё бы ничего, если бы нужна была анимация, в которой бы нужно было менять только положение и размеры картинок. Мне требовалось сделать анимацию, в которой бы плавно менялась их прозрачность. Тут-то и обнаружились новые фокусы.

AlphaImageLoader


Если вы в курсе, что такое AlphaImageLoader и как устроены png.htc, то можете сразу перейти к следующей части. Ну а для тех, кто не в курсе — постараюсь кратко объяснить механизм работы png.fix.

В своих браузерах MS, как и другие разработчики, любит встраивать какие-нибудь особенные фишки. Одна из этих фишек (начиная с версии 4.0) — это фильтры для создания «multimedia-style visual effects» (подробности в MSDN). Начиная с версии 5.5 в IE присутствует фильтр AlpahaImageLoader (подробности в MSDN), с помощью которого между фоном и контентом объекта можно отобразить картинку, в том числе и png с прозрачностями. Используя этот фильтр совместно с JS можно автоматизировать процесс загрузки png в IE 5.5 и 6.0. Самый распространенный способ выглядит так:

function PngForIe(elem)
{
  elem.style.filter = "progid:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' + elem.src + ');"
  elem.src=blank; //в blank должен находиться адрес прозрачного гифа размером 1x1.
}

Что делает эта функция? Сначала она размещает правильно загруженную (с помощью AlphaImageLoader) png'шку между фоном и неправильно загруженной (той, которую мы фиксим). А потом она заменяет неправильную картинку на абсолютно прозрачную. И мы видим именно то, что и хотели увидеть — нормальную png'шку:

Для того, чтобы размеры картинки менялись так, как этого требуют стили, нужно в AlphaImageLoader добавить параметр sizingMethod='scale'.

Теперь мы можем не бояться png'шек и даже смело их анимировать изменяя положение и размеры (правда, при их изменении придется запускать фикс заново). Но что произойдет, если мы захотим поменять прозрачность этой картинки? Ведь прозрачность в IE (5.5 — 7.0) тоже задается через фильтры.

Filters и неоправдавшиеся надежды


Переходим к самому интересному.
Пробуем добавить к исправленной картинке фильтр alpha, рассчитывая на то, что коэффициенты прозрачности картинки и прозрачности перемножатся и… получаем совсем не то, чего ожидали! Косяков появляется сразу несколько в зависимости от того, что мы пытаемся делать с картинкой:

Что же мы видим?
Первая картинка (alpha(opacity='100')) стала непрозрачной везде, где коэффициент непрозрачности был больше 0.
Вторая картинка alpha(opacity='70') на первый взгляд почти не отличается от оригинальной, но если присмотреться, то можно заметить, что сглаженные края пропали и цвета осталось ровно два. На самом деле, непрозрачность 70% (opacity — это именно коэффициент непрозрачности: 0% — прозрачный, 100%- непрозрачность) совпадает с этой характеристикой большей части исходной картинки.
Таким образом, если картинка отображается в оригинальном размере, то те пиксели, которые были абсолютно прозрачными, такими и остаются, а прозрачность остальных становится равной значению параметра opacity фильтра alpha (в процентах). А значит все преимущества png перед gif теряются.
Но то, что происходит на третьей картинке отбивает желание использовать png напрочь. При попытке одновременного ресайза картинки и изменения ее прозрачности то, что было абсолютно прозрачным вдруг становится черным!

Стоит отметить, что косяки появились и в IE7, который изначально довольно дружелюбно относится к png. Более того, появляется еще один глюк, о котором написал в комментах l2k:
Если использовать alpha-фильтр на тексте (который по умолчанию в IE7) со сглаживанием (antialiasing) — то получаем на выходе те-же косяки, что и в примере «Filters и неоправдавшиеся надежды». То есть, вместо красивого прозрачного шрифта — получаем полужирный ступенчатый шрифт без сглаженностей (antialiasing).

Кто виноват и что делать


Если есть проблема, то нужно с ней как-то бороться. Поскольку мне требовалось сделать анимацию всего-то из 5 слайдов, то первая мысль, которая пришла в голову — это честно сделать 5 картинок с разной прозрачностью и загружать их просто AlphaImageLoader'ом. Но подмена картинок означает, что картинки, используемые в анимации, надо заранее подгрузить. В принципе, ничего сложного в этом нет, но я решил, что стоит поразмылсить дальше.
Следующий вариант был забить на png и использовать gif. В этом случае потеряется округлость, но ничего особо страшного не произойдет. Но мы же не ищем легких путей!

А дальше вот какая мысль пришла мне в голову. Мы не умеем умножать или делить прозрачность, но зато мы можем ее складывать! А значит можно сделать одну картинку в пять раз более прозрачную, чем исходная и разместить 5 ее экземпляров друг над другом, а при анимации просто поочередно делать ей display:none.

Вот здесь можно посмотреть — что из этого получилось, а также увидеть откуда взялись скриншоты (смотрите через IE или ничего не увидите).

P.S. Посмотрел, как на всё это реагирует IE8. Косяков с фильтрами не обнаружил, однако то, что он не понимает style=«opacity:0.7» огорчает
Tags:
Hubs:
+28
Comments 40
Comments Comments 40

Articles