Le format PNG autorise jusqu’à 256 niveaux de transparence qui ne sont pas pris en charge par Internet Explorer 6. La dégradation grâcieuse n’étant pas toujours possible, je me suis rafraichis la mémoire sur les différentes manières d’utiliser le filtre *AlphaImageLoader*. J’ai fini par tomber sur une solution globale pour gérer cette transparence même en présence d’un *background-repeat* ou d’un *background-position* ! (Cet article est en quelque sorte la suite de Opacité CSS et effet de trame avec GIF/PNG transparent.)
Le format PNG
Le PNG est format d’enregistrement d’image destiné à remplacer le format GIF dans sa version 8 bits. La version 24 bits en RVBa — qui comprend plus de 16 millions de couleurs — autorise jusqu’à 256 niveaux de transparence très utiles en webdesign pour superposer deux images dont celle du dessus laisse transparaitre celle du dessous.
Malheureusement, IE6 ne comprend rien à ces différents niveaux de transparence : il faut ruser, c’est usant. Certains préconisent la dégradation grâcieuse : utiliser la transparence dans les navigateurs qui la prennent en charge et servir autre chose au dernier de la classe : un PNG 8 bits avec une seule couleur de transparence, fusionner les deux images censées se superposer, voire même utiliser une image légèrement différente.
Après tout, les visiteurs ne sont pas toujours des développeurs web utilisant plusieurs versions de navigateurs pour traquer la moindre différence de rendu. Si vous pouvez vous le permettre, foncez ! Dans le cas contraire, il faudra recourir à des solutions plus ou moins fonctionnelles selon que l’image en question se trouve placée en `background` d’un élément (une `div`, par exemple) ou dans une balise `img`. Si votre image transparente est placée sur un fond uni, il reste la possible de modifier l’image par voie logicielle :
Modifier le chunk (segment) bKGD des png
Un image au format PNG est composée de différents segments (chunks) dont le fameux bKGD qui spécifie une couleur de fond par défaut. A noter que les agents utilisateurs (navigateurs, logiciels, etc.) ne sont pas tenus de respecter cette couleur et peuvent en utiliser une autre. Dans IE6, cette couleur se rapproche d’un gris-vert tirant sur le turquoise…
Certains logiciels comme TweakPNG permettent de modifier la valeur de bKGD. Si vous disposez d’un fond de couleur uni, il suffit d’y mettre la couleur du fond sur laquelle est placé votre image contenant des zones transparentes.
Dans le cas contraire, les filtres Microsoft sont nos amis :
Le filtre `AlphaImageLoader` de Microsoft
Internet Explorer (depuis la version 5.5) inclut un mécanisme de filtres propriétaires `filter` dont *AlphaImageLoader* qui gère la transparence des png 24 bits. L’utilisation du filtre diffère selon que l’image est appelé via la balise `img` ou en tant que `background` d’un autre élément.
Appliqué sur une balise `img`
Applique le filtre sur les images dont la classe CSS est `.img_png` à l’intérieur d’une feuille de style réservée à IE6 avec les commentaires conditionnels. Il suffit de renseigner la source de `monImageTransparente.png` dans la variable `src` :
.img_png {
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pix/monImageTransparente.png', sizingMethod='image');
}
Appliqué sur une image en `background`
Pour les navigateurs tenant compte de la transparence, vous aurez la règle CSS :
.div_png {
width: 100px;
height: 150px;
background: url(../pix/monImageTransparente.png) no-repeat;
}
Pour Internet Explorer 6, il faudra utiliser :
.div_png {
width: 100px;
height: 150px;
background: none;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='pix/monImageTransparente.png', sizingMethod='scale');
}
Notez l’attribut *sizingMethod* qui peut recevoir les valeurs *image*, *scale* ou *crop* (via l’excellente FAQ du forum d’Alsacréations.) :
- image — Réduit ou élargit le bloc pour correspondre aux dimensions de l’image (valeur par défaut),
- scale — Etire l’image aux dimensions du bloc,
- crop — Rogne l’image pour qu’elle tienne dans le bloc.
Quelques contraintes
1. La source de l’image doit être relative au document HTML qui l’affiche et non à la feuille de style CSS qui la réclame. De sorte qu’une image se trouvant dans un dossier *images* appelée dans un fichier CSS se trouvant dans un dossier *css* ne devra plus se trouver sur le chemin *../pix/monImageTransparente.png* mais sur *pix/monImageTransparente.png*.
2. Les liens contenus dans un élément HTML possédant une images de fond transparente ne sont plus cliquables, les champs `input` ne sont plus accessibles et le texte n’est plus sélectionnable. Une manière générale d’y remédier est d’ajouter une déclaration du type :
.div_png a,
.div_png input {
position: relative;
z-index: 1;
}
Pour plus d’information sur cette question, lire le fil de discussion paru sur le forum d’Alsacréations et la synthèse rédigée par Frank Galey.
3. Il n’est pas possible d’utiliser les propriétés *background-repeat* et *background-position* avec une image PNG transparente en `background`.
4. Il est difficile d’utiliser des événements de style *rollover* pour permuter des images de fond au passage de la souris.
Passez-moi l’expression !
C’est assez contraignant. Heureusement, le web est rempli de gens de bonnes volonté qui se sont retroussé les manches pour nous offrir des solutions sur un plateau. Voyez plutôt :
* html img,
* html .png {
position:relative;
behavior: expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "', sizingMethod='image')",
this.src = "transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "', sizingMethod='crop')",
this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
);
}
Trouvé sur komodomedia via babylon-design.
Le `* html` est là uniquement pour cibler IE6. Vous pourrez donc vous en passer si vous utilisez une feuille de style dédiée à ce navigateur. Ne fonctionne pas si Javascript est désactivé. Nécessite une image transparente de 1px de côté (*transparent.gif*).
Note : il sera peut-être nécessaire d’ajouter un `z-index: 1;` pour éviter les problèmes de liens, d’éléments de formulaire ou de sélection de texte évoqués plus haut.
Une solution globale avec iepngfix
Il existe de nombreux scripts permettant d’automatiser avec plus ou moins de bonheur cette gestion de la transparence des images PNG. Ils mettent tous en oeuvre le filtre *AlphaImageLoader* soit dans un fichier Javascript, soit dans un fichier HTC. Parmi tous les scripts existants, j’ai retenu iepngfix de TwinHelix que m’a conseillé Oncle Tom sur Twitter.
Ce composant HTC gère la plupart des contraintes énoncées plus haut, y compris l’absence de prise en compte de *background-repeat* et *background-position* dans iepngfix version 2.0 Alpha 3.
Le script est très simple à utiliser :
Copiez les fichiers *iepngfix.htc* and *blank.gif* dans le dossier de votre site web,
Copiez la déclaration CSS suivante dans votre feuille de style ou votre fichier HTML :
img, div { behavior: url(iepngfix.htc); }
Vous pouvez placer dans ce sélecteur CSS toutes les balises HTML, les identifiants ou les classes pour lesquels vous désirer activer la gestion de la transparence des PNG. Séparez-les simplement par une virgule.
N’oubliez pas que le chemin vers les fichiers *iepngfix.htc* et *blank.gif* est relatif au document HTML et non à la feuille de style CSS.
Si votre site est composé de sous-dossier, n’hésitez pas à ouvrir le fichier *iepngfix.htc* dans un éditeur de texte pour modifier la variable `blankImg` afin de la faire pointer vers votre pixel transparent. Par exemple : `IEPNGFix.blankImg = ‘/images/blank.gif’;`
Cette fois encore, le chemin doit être relatif au document HTML. Si vous désirez activer la prise en charge des propriétés *background-repeat* et *background-position* assurez-vous d’inclure le fichier Javascript *iepngfix_tilebg.js* dans votre document HTML :
<script src="iepngfix_tilebg.js" type="text/javascript"></script>
Dans certains cas, il sera nécessaire d’envoyer le bon type MIME à Internet Explorer 6. L’auteur du script a prévu un fichier *iepngfix.php* qui inclut le fichier *iepngfix.htc* tout en renvoyant le type MIME `text/x-component` associé aux fichiers `.htc` :
img, div, a, input { behavior: url(/css/resources/iepngfix.php); }
Pour améliorer les performances, soyez le plus sélectif possible : préférez un `#img_header` ou un `.img_png` à l’utilisation de la balise `img` seule, sauf bien sûr si toutes vos images ont besoin du script !
Il se peut que le fond gris-vert apparaisse brièvement lors du chargement de l’image. Si vous ne voulez pas ce comportement (notamment sur les grandes images), vous n’aurez qu’à revenir à une utilisation « manuelle » du filtre *AlphaImageLoader* comme indiqué dans la première partie.
N’hésitez pas à consulter le fichier *iepngfix.html* présent dans l’archive *.zip* qui apporte une palanquée d’informations, de trucs et d’astuces pour utiliser le script et remédier aux problèmes d’utilisation.
Une nouvelle solution globale avec DD_belatedPNG
DD_belatedPNG semble faire l’unanimité autour de lui pour sa légèreté et son efficacité, y compris lorsqu’on l’utilise avec `background-position` ou `background-repeat`. Le script s’utilise très simplement :
<!--[if IE 6]> <script src="DD_belatedPNG.js"></script> <script> DD_belatedPNG.fix('.png_bg'); </script> <![endif]-->
La classe `.png_bg` n’est qu’un exemple et vous pourrez utiliser un ou plusieurs sélecteurs à votre convenance, tels que :
<script type="text/javascript"> // <![CDATA[ DD_belatedPNG.fix('.example1, .example2, img'); // ]]></script>
Conclusion
Ce sujet semble inépuisable, ce qui n’est pas mon cas. Je laisse cet article en version *bêta* pendant quelques temps histoire de laisser décanter le sujet : il serait étonnant que des erreurs ou inexactitudes ne se soient pas glissées sous le tapis de souris 😉
Ressources externes
Généralités sur le format PNG
Gérer la transparence du PNG par voie logicielle
: Ce logiciel permet d’accéder aux informations contenues dans un fichier PNG dont notamment le chunk (segment) bKGD pour modifier la couleur de fond sur laquelle s’applique la transparence (un fond gris/vert/turquoise par défaut dans ie6). Vous trouvez quelques explications concernant son utilisation sur
: Logiciel très pratique et simple d’emploi pour améliorer la compression des images au format PNG. Il suffit de faire glisser les images que vous voulez améliorer et le PngOptimizer s’occupe du reste. Possède quelques options pour manipuler les *chunks* ou garder une version de l’image d’origine.
: C’est peu connu, mais les spécifications du format PNG 8 bits autorisent plusieurs couleurs dans le segment Alpha, ce qui permet de spécifier plusieurs couleurs transparentes en utilisant un logiciel approprié comme Fireworks. Voilà une bonne technique pour s’autoriser une dégradation grâcieuse des images transparentes sous Internet Explorer 6 !
: Un peu hors-sujet par rapport à la transparence des PNG, je signale l’existence d’un plugin pour Photoshop qui permet d’optimiser le poids des images PNG : le plugin installé par défaut dans Photoshop ne rend pas vraiment justice aux possibilités de compression de ce format.
Quelques scripts
: Version 1.0 et version 2.0 Alpha 3 du script iepngfix. Gère les *background-repeat* et *background-position* dans la version *Alpha* à l’aide d’un fichier Javascript supplémentaire.
: Ce script est proposé par Yves Van Goethem. Nombreuses options disponibles réservées à un public averti 😉
: Fichier Javascript gérant la plupart des pièges posés par l’application du filtre `AlphaImageLoader`.
: Avec Unit PNG Fix pas besoin de définir des classes ou de cibler vos éléments. Fonctionne avec les balises img ou sur les background-image. Très léger. Merci à 13sportif pour le lien.
: Expression Javascript permettant de gérer la transparence des PNG en `img` ou en `background`
: Script très léger et pratique. S’applique à toutes les images PNG de votre document. Toutefois, certaines images restent en mode *téléchargement* alors quelles sont bien affichées, ce qui peut donner l’impression au visiteur que quelque chose ne tourne pas rond sur le site. Malgré tout, ce script vieillissant peut encore rendre quelques services : il m’a rappellé l’existence de l’attribut `defer= »defer »` de la balise `script` qui permet de différer le chargement (ou l’application) du script en question. Voir cet article très complet sur l’analyse de *defer*.
: Propose une version modifiée du script précédent pour les champs de formulaires `
`
: Encore un Javascript à se mettre sous la souris ! Crée une balise `div` dans laquelle est affichée l’image traitée par le filtre DirectX :
: Plus ou moins la même chose avec un composant HTC.
: Une solution originale en PHP.
Autres ressources sur la transparence des PNG
: La blonde propose avec pédagogie un récapitulatif des différentes méthodes pour gérer cette transparence sur 256 niveaux.
: Présente de nombreuses solutions et contournement pour afficher les images transparentes.
: La FAQ du forum Alsacréations sur comment obtenir la transparence des PNG avec Internet Explorer 6
: Tutoriel pour pallier les effets secondaires du filtre AlphaImageLoader en cas de positionnement absolu.
: Mise en garde d’Eric Daspet sur l’utilisation des filtres : Si vous l’utilisez pour une petite icône de présentation qui apparaît vingt fois dans votre page, c’est vingt exécutions du filtres qui sont faites. À chaque exécution du filtre le rendu est bloqué, en attente. Sur Yahoo! Search en retirant AlphaImageLoader de la feuille CSS c’est jusqu’à 100ms qu’ils ont gagné (information donnée par Stoyan Stefanov sur sa dernière présentation).
: Article très instructif sur la transparences du format PNG et l’application de `AlphaImageLoader`
Une petite erreur c’est glissé dans ton billet … PNG 8 gère aussi la transparence alpha 🙂
http://www.libpng.org/pub/png/
« full alpha transparency in 8- and 16-bit modes, not just simple on-off transparency like GIF »
De plus je ne recommande pas du tout l’utilisation d’expression CSS dans IE, ça donnera bien sur le poste de votre client qui tourne sur XP et qui dispose de 4Go de DDRAM, mais la pauvre mémé qui se trouve sous Win2000 et qui possède que 512Mo de DDR, ne sera pas très heureuse de ne pouvoir accéder à son site de recette favoris parce qu’un développeur à cru bien faire …
@Yves Van Goethem: Merci Yves, c’est corrigé (enfin, j’ai juste supprimé l’information concernant le canal Alpha pour le PNG 24 bits, parce que sinon, ça me faisait recommencer toute la phrase).
Bravo pour ce récapitulatif et merci pour la référence à mon billet 😉
Merci pour ce récapitulatif, j’en connaissais une majeur partie, mais rassembler tout sur une page est plus que pratique.
Je vais faire dans l’original 🙂
Bravo pour ce récapitulatif 🙂
Merci également pour la citation 😉
AlphaImageLoader – et toutes les techniques css / js / htc qui l’utilisent, dont iepngfix, pnghack et les autres – posent de réels problèmes de performance. Le filtre est appliqué à chaque occurence de l’image. Un fond qui apparait 15 fois c’est 15 représentations de l’image en mémoire, et autant d’exécution du filtre. Ca peut réellement amener à des problèmes sur des machines peu puissantes (qui sont celles qui sont les plus fréquentes avec IE6 puisque IE7 est par défaut sur les récentes).
Expression est encore pire car il se re-exécute à chaque reflow, donc très fréquemment. Il y a des astuces qui réécrivent la règle CSS expression de façon à la supprimer après la première exécution mais c’est finalement assez peu utilisé (et ça reste peu performant).
http://performance.survol.fr/2008/07/ne-pas-filtrer-les-pngs/
Dans tous les cas, n’utilisez pas le filtre (ou l’expression) directement en CSS, utilisez toujours un hack CSS afin de vous assurer que IE7 et IE8 n’exécutent pas inutilement le filtre.
Il y a aussi la possibilité d’utiliser un PNG8 avec des transparences binaires et des couches alpha. Seul IE6 ne saura pas interpréter nativement l’image, mais il dégrade assez correctement : il remplacera toutes les couleurs avec une couche alpha par du pur transparent. Si vous étudiez bien vos images ça sera un peu moins joli, mais tout à fait acceptable. Si vos transparences non binaires sont pour les bords des images, des transitions ou des fondus, c’est même parfait.
Plus d’infos sur http://www.sitepoint.com/blogs/2007/09/18/png8-the-clear-winner/
Ou via jQuery : http://jquery.andreaseberhard.de/pngFix/ ou http://jquery.khurshid.com/ifixpng.php
$(document).pngFix(); c’était dur hein ? :p
En tout cas, c’est clair Eric. Moins y’a de js sur une page, mieux les navigateurs se portent.
Tu n’a pas fait mention de “Unit PNG Fix” !
C’est aussi un excellent script, selon moi :
http://labs.unitinteractive.com/unitpngfix.php
Merci à @jeFFF, @La Blonde et @Frank pour vos encouragements 😉
@Eric: Cool, ces précisions concernant les expressions javascript dans les CSS. J’ai ajouté le lien vers SitePoint sur l’utilisation de Fireworks et des couleurs de transparence multiple en restant en png8.
@Kud: Yep, j’ai fais l’impasse sur les déclinaisons avec jQuery parce qu’au final, ces scripts reprennent les mêmes principes, mais c’est vrai que ça peut être intéressant de voir ça de plus près.
@13sportif: Excellent lien qui avait réussit à échapper à ma vigilance. Je l’ai ajouté dans les ressources externes.
Pour ma part, pour m’en tenir à des méthodes générant un code le plus propre possible tout en garantissant des CSS syntaxiquement valides, je privilégie deux méthodes :
la méthode JavaScript pour les images en PNG 24 avec couche Alpha codées en dur (élement
img
) ;l’utilisation, en cas d’image gérée en CSS, d’une image d’arrière-plan de substitution, appelée par une feuille de style ciblant IE 6 (donc appelée par un commentaire conditionnel), au moyen de la propriété
background-image
, et ce sans utiliserbehavior
nifilter
(qui, rappelons-le, invalident la feuille de style, le validateur CSS du W3C indiquant alors que ces propriétés n’existent pas ; de plus, leur nommage n’est pas conforme à la syntaxe des propriétés et extensions propriétaires telle que prévue par la spécification CSS 2.1, même si IE 8 fait un effort dans ce sens en introduisant-ms-filter
et-ms-behavior
, entre autres).Bref, comme le dit si bien un de mes anciens collègues de travail, les hacks, c’est pas bien ! 😉
Beau billet Bruno,
Mais je ne peux m’empêcher de penser que ce n’est pas aider les gens que d’adapter son site à IE6…
Perso je n’utilise pas ces méthodes, que les utilisateurs d’ie 6 aille se faire voir … 🙂
Note que le PNG gère la transparence en 32 bits et non en 24. Le format RGBA intègre bel et bien 4 composantes 8 bits, ce qui fait 32 bits et non 24. Pour ce qui est du PNG palettisé, la palette est là aussi en 32 bits, la composante A encodant la transparence pouvant elle aussi être exploitée, même si je ne connais aucun logiciel de retouche d’images qui le gère. En revanche, j’ai déjà utilisé cette capacité de stockage de l’alpha sur certains jeux vidéo où les textures palettisées sont bienvenues pour une question d’économie de place, en particulier avec une composante de transparence. C’étaient alors des moulinettes internes qui géraient les conversions de formats.
@Martin: C’est la spécification elle-même qui parle de 8bits et de 24bits. On parle là de nombre de couleurs possibles. après effectivement une couleur est elle-même codée en RGBA, donc sur 32bits, mais c’est un tout autre sujet.
C’est bien dommage qu’IE6 n’est pas correctement pris en charge les images PNG, ça a empêché le développement de sites « design » avec tout les effets d’ombres et de superposition.
Merci pour la qualité de cet article complet !!!
:-*
Simplement migrez, abandonnez ce désuet IE 6 pour Chrome ou firefox ou encore IE 8 !!!