PNG и прозрачность

Автор: Евгений Рыжков Дата публикации: 22.01.2009

Проблема

IE 6 не отображает корректно прозрачность PNG-24 (альфа канал).

png в нормальных браузерахВот так png-24 отображается
«нормальными» браузерами
png в ie6Вот так отображает png ИЕ6
(прозрачные участки заливает серым фоном)

Эта картинка в оригинале — тест на поддрежку прозрачности png.

Заметка: PNG-24 иммет ряд преимуществ перед GIF и PNG-8, где прозрачность в ие корректно отображается:

  • PNG-24 может обеспечивать альфа-прозрачность (256 уровней прозрачности), в отличии от GIF и PNG, где всего два уровня — абсолютно прозрачно и абсолютно не прозрачно
  • поддерживает миллионы цветов

Решения

Метод 1 — применение фильтра AlphaImageLoader

1.1. Для фонового изображения

CSS код:

.block {
background-image: url(images/pngtest.png); /* для нормальных браузеров */
width: 173px;
height: 173px;
}
* html .block { /* хак для ie6 */
background: none; /* убираем обычный background */
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/pngtest.png'); /* png с прозрачностью для ие6 */
}

Параметр src указывает путь к файлу изображения. Фильтр может иметь дополнительный параметр sizingMethod, который указывает, если изображение не соответствует размерам элемента, в который оно загружается:

  • crop — обрезать изображение, если оно больше размеров объекта родителя
  • image — увеличить или уменьшить объект по размеру изображения (по умолчанию)
  • scale — изменить масштаб изображения по размеру родителя

Пример:

* html .block {
background: none;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pngtest.png', sizingMethod='crop');
}

Плюс — просто в реализации.

Минусы:

  • требует хак для IE6
  • не проходит валидацию
  • замедляет работу браузера (об этом будет написано подробнее позже)
  • некотрые трудности со слоями z-index
  • нет возможности использовать background-repeat
  • нет возможности использовать background-position

Возможные проблемы:

При использовании фильтра в ие6 не отображается фоновый рисунок

Этот баг возможен из-за неверно указанного пути к файлу. Чтобы картинка 100% находилась используем полный путь к файлу:

filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://site-name.com/images/pngtest.png');

Второй вариант (более универсальный) — использовать тег <base> для составления корректных относительных адресов, а путь в фильтре относительный, начиная со слеша:

filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/pngtest.png');
При использовании фильтра в ие6 становятся не кликабильными вложенные элементы (ссылки, кнопки)

Пример — ссылка на фоне с AlphaImageLoader (демо для ие). HTML код:

<div><a href="http://site-name.com/">Название сайта</a></div>

CSS код:

div { padding-top: 20px; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pngtest.png'); width:200px; height:200px; }

Решения:
1. Иногда помогает, если прописать вложенным элементам свойство position: relative;

a { position: relative; }

Результат

2. Если применять AlphaImageLoader для элементов со свойствами position: absolute или position: relative, тогда для вложенных элементов предыдущий способ не помогает:

div {
padding-top: 20px;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pngtest.png');
width:200px;
height:200px;
position: absolute;
top: 0;
left: 200px;
}
a {
position: relative; }

Результат. Решение — выносить фоновый рисунок в отдельный div:

<div>
<a
href="http://site-name.com/">Название сайта</a> <div></div> <--фоновый рисунок-->
</div>

CSS код:

div {
padding-top: 20px;
position: absolute;
top: 0;
left: 200px;
width: 200px;
height: 200px;
}
div div {

filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pngtest.png');
width:200px;
height:200px;
position: absolute;
top: 0;
left: 0;
z-index: 1; /* явно указываем z слой */
}
a {

position: relative; /* чтобы иметь возможность задать z слой */
z-index: 2; /* задаем z слой больше, чем у блока с фоновым изображением */
}

Результат

В ссылках в IE6 не кликабильны прозрачные части изображений

При использовании прозрачных фоновых изображений для ссылок (например в логотипах), в ие6 нельзя кликнуть по прозрачному участку. HTML для логотипа этого примера:

<a href="/" class="testPNGLogo"></a>

CSS:

.testPNGLogo {
display: block; /* логотип - блок, чтобы задать четкие размеры */
width: 178px; /* задаем */
height: 36px; /* размеры логотипа */
margin: 20px;
background: url(pngLogo.png); /* рисунок ссылки (логотип) */
}
* html .testPNGLogo {
/* показ логотипа для ие6 */
background: none;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pngLogo.png');
}

Решение — не используем фон с прозрачностью непосредственно для тега a. HTML:

<a href="/" class="testPNGLogo"><span></span></a>

CSS:

.testPNGLogo { /* для ссылки не устанавливаем фон */
display: block;
width: 178px; /* размеры равны */
height: 36px; /* размеру логотипа */
margin: 20px;
}
.testPNGLogo span {

display: block; /* чтобы установить размеры строчному элементу */
width: 100%; /* заполянем всю площадь логотипа */
height: 100%;
background: url(pngLogo.png); /* рисунок задаем для вложенного элемента */
cursor: pointer; /* чтобы на всем логотипе был нужный указатель мыши */
}
* html .testPNGLogo span {
/* png для ие6 */
background: none;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pngLogo.png');
}

1.2. Применение AlphaImageLoader для картинок (img). HTML:

<img src="pngLogo.png" style="filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pngLogo.png' width:expression(1); height:expression(1); " />

Пример.Плюс — работает. Минусы:

  • виден кусочек основного рисунка —
  • значительно замедляет работу браузера (альфа фильтр + 2 expression)
  • замедляет отображение страницы, из-за не указынных явно размеров картинки. Если задать размер картинки, баг с куском основного рисунка увеличивается —
  • не работают нормально ссылки на таких рисунках (некликабильны прозрачные участки)
Метод 2 — замена фона прозрачным gif скриптом (behavior)

Первоисточник.

Для этого воспользуемся механизмом behavior, не являющийся стандартом CSS, но позволяющий описать поведение стиля в зависимости от событий, которые происходят при отображении веб-страницы. Поддерживает IE5+. Необходимые действия:

  1. добавляем в свой проект файл (например сохраняем в корень) iepngfix.htc (3.2 Kb) - скрипт для замены серого фона на прозрачный
  2. сохраняем blank.gif (52 b) - прозрачный gif размером 1х1, которым будет заменен серый фон в IE
  3. изменяем в iepngfix.htc путь к файлу blank.gif на свой
  4. создаем класс .png { behavior: url(<путь к файлу>/iepngfix.htc); }
  5. применяем этот класс для png-изображений с альфа прозрачностью

CSS код:

.png {
behavior: url(iepngfix.htc);
}

HTML код:

<img src="pngLogo.png" class="png" width="178" height="36" />

Результат. Для избежания значительного замедления работы браузера, применяем этот метод только к картинка с прозрачностью. Для того чтобы замедления сказывались только для IE6 используем условные комментарии. Преимущества:

  • компактный код
  • ссылки на таких изображениях работают нормально

Недостатки:

  • при загрузке страницы пользователь, до отработки скрипта, видит картинки с серым фоном
  • замедляет работу браузера (IE)
  • замедляет скорость загрузки страницы (IE)
  • часто требует явного указания размера картинки (width и height)
  • в «чистом» виде не позволяет реализовать background-repeat и background-position
  • не проходит валидацию
Метод 3 — PNG прозрачность в IE6 с background-repeat и background-position (DD_belatedPNG)

Drew Diller предложил использовать скрипт, который позволяет использовать прозрачный png в ие6 «по настоящему»:

  • позволяет использовать прозрачность в картинках (img)
  • кликабильна вся область ссылок-картинок (включая прозрачные участки)
  • позволяет использовать в фоновых изображениях свойства background-repeat и background-position
  • нет проблем с z-слоями
  • легкий скрипт

Чтобы заработало:

  1. подключаем скрипт DD_belatedPNG.js (5.4 Кb) к странице
  2. вызываем функцию DD_belatedPNG.fix, в качестве аргументов перечисляем классы элементов, в которых используется прозрачный png
<!--[if IE 6]>
<script src="js/DD_belatedPNG.js"></script>
<script>
DD_belatedPNG.fix('.png_bg, .png_img'); <!--перечисляем классы элементов-->
</script>
<![endif]-->

Пример использования с background-postion:

<html>
<head>
<title>
Пример использования с background-postion</title>
<
style type="text/css">
.div {
width: 173px; /* размеры */
height: 346px; /* блока */
background: url(test.png); /* фон с прозрачностью */
background-position: 0 100px; /* задаем позицию фону */
background-repeat: no-repeat; /*запрещаем повторение фона */
}
</style>
<!--[if IE 6]>
<script src="js/DD_belatedPNG.js"></script>
<script>
DD_belatedPNG.fix('.div'); <!--указываем нужные классы-->
</script>
<![endif]-->

</head>
<body>
<div
class="div"></div>
</body> </html>

Результат. Недостатки:

  • не отрабатывает, если блок скрыт (display: none / visibility: hidden). В таком случае понадобится вызывать DD_belatedPNG.fix повтороно, после показа блока
  • вообще, при использовании динамических эффектов нужно с DD_belatedPNG быть внимательным. Иногда проще и надежней использовать filter
  • несколько замедляет скорость загрузку страницы
  • update 21.05.10 by Анрей Косяк: не сработает скрипт, если background будет указан с !important
Метод 4 — PNG прозрачность в IE6 на jQuery

Первоисточник. Применение:

  1. подключаем популярную библиотеку jQuery
  2. подключаем скрип jquery.pngFix.js (2.5 Kb)
  3. инициализируем скрипт при загрузке страницы
<html>
<head>
<style
type="text/css">
.div {
width: 173px; /* размеры */
height: 173px; /* блока */
background: url(../images/ie6/pngtest.png); /* фон с прозрачностью */
}
</style>
<script
type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="resources/jquery.pngFix.js"></script>
<script
type="text/javascript">
$(document).ready(function(){
$(document).pngFix();
});
</script>
</head>
<body>
<div
class="div"></div>
</body>

Недостаки:

  • при загрузке пользователь некотрое время видит картинки с серым фоном
  • не работает background-position и background-repeat
  • довольно тяжелый файл библиотеки
  • увеличенное время на загрузку страницы (два дополнительных файла)
Метод 5 — PNG прозрачность в IE6 на pie

Еще один вариант научить IE6 прозрачности в png24 — использовать библиотеку PIE.

Примение:

  1. Качаем дистрибутив PIE.
  2. Добавляем файл PIE.htc в свой проект.
  3. Прописываем правила для нужных элементов:
.phgFix {
     background: url('i/address.png') no-repeat;
     -pie-background: url('i/address.png') no-repeat;
     behavior: url(PIE.htc);
}

update 28.06.11 by mrjek Или можно воспользоваться более универсальным вариантом:

.phgFix {
     background: url('i/address.png') no-repeat;
     -pie-png-fix: true;
     behavior: url(PIE.htc);
}

Достоинства:

Недостатки: