IE6 — Gérer la transparence du format PNG 24 bits

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 :

  1. Copiez les fichiers *iepngfix.htc* and *blank.gif* dans le dossier de votre site web,

  2. 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.

  3. 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.

  4. 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>
    
  5. 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);
        }
    
  6. 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 !

  7. 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`