De quoi parle-t-on ?

On parle de technicités absconses pour le non-webeux. Je vais tenter une petite explication simplifiante, sans garantie de résultat... n'hésitez pas à laisser tomber si vous décrochez.

Une page d'un site Web est décrite par un document dans le langage HTML. Mais le contenu d'une page web est rarement entièrement véhiculé par ce document HTML. C'est notamment le cas des images, mais aussi des animations Flash, des scripts, des feuilles de styles, etc. Tous ces contenus (génériquement appelés ressources) sont décrits dans d'autres fichiers, auquel le document HTML fait référence.

Par exemple, la page d'accueil du site basicpower est un document HTML qui fait référence à une feuille de styles sous le nom http://www.basicpower.fr/basicpower.css, ainsi qu'à diverses images sous les noms http://www.w3.org/Icons/valid-xhtml10-blue, http://www.basicpower.fr/basicpower.png, etc.

L'idée de ressources embarquées (en anglais embedded ou inline) est de ne plus placer ces ressources dans des fichiers séparés, mais de les inclure à l'intérieur même du code HTML de la page. Ou à l'intérieur du code CSS d'une feuille de styles, le cas échéant.

A quoi ça sert ?

Bonne question. Le fait qu'une image, une feuille de styles, etc. soit dans un fichier séparé présente des avantages : ça ne prend pas dans le document HTML que la place du nom de la ressource; si on veut modifier une ressource utilisée par plusieurs pages Web, il suffit de le faire une fois; les systèmes de cache permettent d'économiser les transmissions d'une ressource utilisée par plusieurs pages Web... Alors ?

On aura intérêt à embarquer les ressources dans un document HTML et CSS si on veut qu'il soit autonome. C'est-à-dire quand le fait que le document HTML ou CSS ne nécessite pas la présence de fichiers auxiliaires, est plus important que les avantages des fichiers séparés. Les exemples d'un tel impératif ne sont pas légion, et pas toujours indiscutables. En voici deux, qui au fond se ressemblent.

Un exemple est le cas où on veut écrire une page Web ou une feuille de styles, qu'on souhaite ensuite mettre à la disposition des autres pour un usage en l'état. C'est-à-dire que les gens qui choisiront d'utiliser cette page ou cette feuille pourront le faire directement, en la plaçant parmi leurs fichiers, et sans la modifier. Dans ce cas, non seulement c'est pratique de ne pas avoir à trimballer, à côté de la page ou de la feuille, des fichiers secondaires. Mais surtout, l'emplacement de ces fichiers secondaires, qu'il faut mentionner dans le document HTML ou CSS, risque fort de varier d'un utilisateur à un autre. Il faudrait donc modifier le document pour en tenir compte.

Je suis tombé sur un tel cas cet été, en tentant de remédier au problème des sites Free bloqués. Je détaillerai ce remède dans un prochain billet.

Un autre exemple est celui des signatures de courrier électronique. Vous savez, les (plus ou moins) jolis cartouches qu'on voit en bas des mails, surtout dans des contextes professionnels, avec le logo de l'entreprise, les coordonnées du correspondant, des liens, etc. Ces cartouches contiennent généralement au moins une image, qu'il est pratique de pouvoir embarquer dans le code HTML de la signature.

En tant que développeur web, je suis amené à réaliser de telles signatures pour mes clients. Il est donc commode de pouvoir leur fournir un fichier autonome, plutôt qu'un fichier pour le code HTML de la signature plus un par image, sans compter les questions d'emplacement de ces fichiers secondaires. Mais il s'agit essentiellement de commodité, puisque les logiciels de mail se débrouillent généralement très bien avec des images stockées ailleurs sur votre disque dur. (Il faut juste ne pas oublier la dépendance entre ces images et la signature, et éviter de supprimer ou déplacer les fichiers intempestivement...)

Comment ça marche ?

Comme on peut le remarquer dans l'exemple du début, les références aux ressources commencent par http:, ce qui indique au navigateur que pour les récupérer il devra ouvrir une connexion au protocole HTTP avec un serveur et lui demander la ressource correspondante. Pour embarquer une ressource dans le document HTML, on utilisera un autre procole, introduit par data:. Suivront les données qui constituent la ressource elle-même.

Par exemple, pour faire une liste à puces dans laquelle on remplacerait les puces par une image (stockée dans un fichier fleche.png, par exemple), on placerait la déclaration suivante dans une feuille de styles (elle-même placée dans un document CSS ou HTML) :
ul.liste_a_fleches {
  list-style-image: url(/images/fleche.png);
}

Ici la mention url(/images/fleche.png) indique que l'image de la flèche est à rechercher à l'emplacement http://meme-serveur-que-la-page/images/fleche.png. En embarquant l'image dans le document contenant la feuille de styles, on remplacera cette mention par url(data:image/png;contenu-de-l-image).

On rencontre deux écueils avec ce procédé :

  1. Les données qui constituent la ressource sont souvent du binaire, qui ne s'insère pas très bien dans un document HTML, qui lui est plutôt du genre texte lisible par un humain.
  2. Les navigateurs ne comprenent pas tous bien le protocole data:.

Codage de la ressource

Pour surmonter le problème des formats binaire-texte, on recode les données constituant la ressource dans un format moins compact que le binaire, mais composé uniquement de caractères compatibles avec un format textuel. Le navigateur se chargera d'effectuer le transcodage inverse pour récupérer la ressource.

En utilisant une version codée de l'image, on pourra écrire la déclaration de style ci-dessus comme suit :

ul.liste_a_fleches {
  list-style-image: url(data:image/png;base64,ICILESDONNEESDELIMAGECODEESENBASE64ETC);
}

On note au passage qu'il n'est pas clair si on peut ou pas insérer des retours à la ligne dans la (potentiellement longue) définition de la ressource. La page Wikipedia qui décrit le protocole data: dit que (la RFC qui définit le protocole dit que) oui, mais mes tests disent que non...

Ceci dit, comment code-t-on une image ou une autre ressource en Base64 ? Comme je le mentionnais au début de ce billet, on utilise l'utilitaire d'encodage écrit par GreyWyvern. Cet utilitaire est bien pratique : on lui donne l'adresse d'un fichier contenant une image, il fournit la chaîne commençant par data: et représentant l'image. Mais il présente un petit inconvénient : il part de l'adresse sur la Toile du fichier contenant l'image; impossible donc d'encoder directement un fichier depuis son disque dur. Il faut au préalable le mettre en ligne quelque part.

Ce n'est pas le bout du monde, mais ce serait si pratique de pouvoir désigner le fichier sur son disque et que tout coule de source ensuite. Donc je l'ai fait. C'est-à-dire que j'ai écrit cet utilitaire, auquel on peut donner un fichier (et non plus seulement son adresse), puis le transmettre à l'outil de GreyWyvern et récupérer le contenu codé en Base64.

Compatibilité avec les navigateurs

C'est le second écueil : Internet Explorer (versions 6 et 7) ne reconnait pas le protocole data: ! Ça refroidit.

Ceci dit, tout n'est pas perdu. Dans le cas d'une signature de courrier électronique, les nouvelles sont meilleures : tous les logiciels de courrier que j'ai testés, y compris Outlook, affichent correctement les signatures embarquant des images.

En ce qui concerne les pages Web, on peut utiliser un autre procédé pour solidariser le texte HTML et les ressources : le MIME HTML ou MHTML. Ce format est reconnu par Internet Explorer... mais pas par Firefox. Donc soudain les choses sont beaucoup plus compliquées, et le prix de la chandelle grimpe en flèche.

En effet, si on veut vraiment fournir une page Web avec des images, qui tienne en un seul fichier, et bien entendu qui marche aussi bien sur Internet Explorer que sur Firefox et les autres, il faut que ce fichier soit un programme PHP (ou similaire), qui détecte le navigateur qui demande la page; s'il s'agit d'Internet Explorer, il servira un document MIME HTML, dans lequel les images seront des attachements; sinon, il servira un document HTML, dans lequel les images seront embarquées. La seule consolation est que dans les deux cas, on pourra utiliser le codage des images en Base64.

J'illustrerai dans un prochain billet ce procédé bifide, à travers mon remède aux sites Free bloqués par manque de page d'index.