Niveau Niveau confirmé

Le schéma Data-URI

Articleweb

Publié par le , mis à jour le (98072 lectures)

images performance sprites data uri url uri

Le but de ce tutoriel est de vous permettre de découvrir ce schéma d'URI, de bien comprendre quand il est utile de l'utiliser et quand il faut l'éviter, et au final de vous donner les outils nécessaires à son utilisation dès aujourd'hui.

Data-URI est un schéma d'URI (Uniform Resource Identifier) contenant directement les données qu'il identifie, contrairement à la plupart des autres schémas. Data-URI est aujourd'hui utilisable en production, bien souvent appelé pour augmenter légèrement les performances de vos sites web à l'aide de données embarquées via data: et encodées en base64. Ces gains ne seront évidemment perceptibles qu'à condition d'utiliser ce schéma de manière pertinente.

Les URI

URI

Avant d'entrer dans le vif du sujet, il est bon de se rappeller ce qu'est un URI (abréviation tenant pour "identifiants uniformes de ressources").

Il ne faut pas faire l'amalgame entre URI et URL : un URL (Uniform Resource Locator) est seulement un sous-ensemble d'URI. Alors qu'un URL est un localisateur de ressource, l'URI est plus largement un identifiant de ressource. Cela signifie qu'un URI sert à identifier une ressource, sans nécessairement indiquer l'emplacement de celle-ci. Ainsi, un URI ne pointe pas nécessairement vers une ressource à télécharger.

Format d'un URI

Selon le standard STD 66, un URI est composé de deux sections obligatoire, et deux facultatives. Celles-ci paraissent sans doute familières puisqu'elles se retrouvent également dans les URLs.

<nom du schéma> : <partie hiérarchique> [ ? <requête> ] [ # <fragment>
  • Nom du schéma (obligatoire) : Le nom du schéma identifie quel schéma d'URI sera utilisé. Des schémas comme HTTP ou FTP vous sont peut-être bien connus, mais bien d'autres, comme TEL, DNS, IMAP, MAILTO, [etc,] et évidemment DATA existent.
  • Partie hiéarchique (obligatoire) : La partie hiéarchique sert à identifier une ressource.
  • Requête (facultatif) : La requête est précédé d'un point d'interrogation et sert à passer des informations supplémentaires à la ressource. Cette section est bien connu sur le web sous le nom de Query String (utilisé notamment avec la méthode GET).
  • Fragment (facultatif) : Le fragment, séparé par un dièse, fournit d'autres informations à la ressources qui seront plus spécifiquement utilisé pour accéder à une ressource secondaire (autrement dit, à une sous-section de la ressource initiale). C'est à cet endroit qu'on retrouve les ancres dans un fichier HTML.
Les différents schémas d'URI ne vous sont sans doute pas inconnus. Entre autre, vous trouverez souvent de ces schémas utilisés sur le web:
  • tel: utilisé pour lancer un appel téléphonique à partir de son appareil (ordinateur, smartphone, etc).
  • mailto: utilisé pour envoyer un courriel à l'adresse définie.
  • javascript: souvent utilisé pour exécuter du code javascript à partir d'un signet (technique appelée "bookmarklet").
  • ws: pour définir une connexion utilisant les websockets.

Tout cela peut paraître légèrement obscur. Toutefois, ce qu'il faut retenir c'est avant tout la syntaxe d'un URI.

Data-URI

Data-URI (RFC 2397) est un schéma d'URI permettant d'inclure une ressource directement au sein d'un fichier comme s'il s'agissait d'une ressource externe. L'avantage de cette technique est de réduire le nombre de requêtes au serveur. La réduction de ces requêtes aide généralement à améliorer de manière conséquente les performances, avec néanmoins des précautions à prendre car le cache n'est pas sollicité de façon habituelle.

Bien qu'en théorie n'importe quelle ressource puisse être utilisée via data-URI, en pratique nous limiterons principalement son utilisation aux images.

Ce schéma a été publié en 1998, et a même été mentionné au sein des spécifications HTML 4.01. Pour ainsi dire, ce n'est pas une technologie récente. Malheureusement, ce schéma fut longtemps ignoré puisqu'il n'est supporté que depuis la version 8 d'Internet Explorer (voir détails ci-après).

Utilisation

Un schéma data-URI peut-être utilisé en lieu et place d'URL au sein de n'importe quel type de ressources web (html, css, javascript). Entre autre, il peut être inclus à ces endroits :

  • <img/>
  • <link/>
  • background-image: url();
  • etc

Le format que prendra une ressource identifiée par un schéma data-URI est le suivant :

data:[<MIME-type>][;charset=<encodage>][;base64],<data>
  • MIME-type (obligatoire) : Le MIME-type représente le type de fichier identifié; par exemple: image/png. Si aucun type n'est spécifié, la valeur par défaut sera considérée comme étant text/plain.
  • encodage (facultatif) : Cette section définit l'encodage des caractères utilisés. Par défaut ce dernier sera US_ASCII.

    Dans la majorité des cas, nous encoderons notre ressource en Base64. Comme ce format d'encodage utilise seulement l'encodage des caractères US_ASCII, la valeur par défaut conviendra. Il sera donc inutile de le spécifier.

  • base64 (facultatif) : Si ce mot clé est présent, nous indiquons que la ressource a été encodée en base64 (nous reviendrons à ce type d'encodage plus bas). S'il n'est pas présent, la ressource sera considérée comme étant encodé en caractères ASCII (URL safe; ce qui n'est utile que pour du texte simple).
  • data (obligatoire) : Cette section contiendra la ressource encodée elle-même.

Exemple

Voici un exemple simple de ce à quoi peut ressembler un data-URI pour une image :

noyau de kiwi du logo Alsacréations

(utilisez votre outil de développement préféré pour voir l'attribut src de cette image dans le code source)

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAAAwFBMVEXm7NK41k3w8fDv7+q01Tyy0zqv0DeqyjOszDWnxjClxC6iwCu11z6y1DvA2WbY4rCAmSXO3JZDTxOiwC3q7tyryzTs7uSqyi6tzTCmxSukwi9aaxkWGga+3FLv8Ozh6MTT36MrMwywyVBziSC01TbT5ZW9z3Xi6Mq2y2Xu8Oioxy7f572qxzvI33Tb6KvR35ilwTmvykiwzzvV36/G2IPw8O++02+btyepyDKvzzifvSmw0TmtzTbw8PAAAADx8fEC59dUAAAA50lEQVQYV13RaXPCIBAG4FiVqlhyX5o23vfVqUq6mvD//1XZJY5T9xPzzLuwgKXKslQvZSG+6UXgCnFePtBE7e/ivXP/nRvUUl7UqNclvO3rpLqofPDAD8xiu2pOntjamqRy/RqZxs81oeVzwpCwfyA8A+8mLKFku9XfI0YnSKXnSYZ7ahSII+AwrqoMmEFKriAeVrqGM4O4Z+ADZIhjg3R6LtMpWuW0ERs5zunKVHdnnnMLNQqaUS0kyKkjE1aE98b8y9x9JYHH8aZXFMKO6JFMEvhucj3Wj0kY2D92HlHbE/9Vk77mD6srRZqmVEAZAAAAAElFTkSuQmCC

Cet exemple en ligne incorpore ce data-URI à l'aide d'une balise img et de la propriété CSS background-image.

L'encodage Base64

Data-URI

Base64 est un type d'encodage (comme md5, sha1, etc) qui permet d'encoder des données binaires en une chaine de caractères ASCII. Son principal avantage est de pouvoir transférer des données complexes (par exemple une image) au travers de médias ne supportant que des données textuelles; comme un URI.

Cependant, il faut noter que l'encodage Base64 n'a accès qu'aux caractères ASCII basiques et donc que les ressources encodées par ce biais pèseront environ 30% plus que leur original. Heureusement, cette différence est réduite à environ 10% après une compression gzip. C'est là une des premières limites du schéma data-URI.

Un exemple intéressant de l'utilisation de l'encodage base64 est l'usage qu'en fait le géant des média-sociaux, Facebook. Ce dernier, lorsqu'il affiche une application tierce sur sa plateforme, par le biais d'une <iframe>, passe un tableau PHP encodé en base64 via une variable GET de l'URL. Ce tableau est ensuite récupéré par l'application et décodé afin d'en extraire des informations utiles à son fonctionnement (nom de la page, ID de l'utilisateur, identifiants de session, etc).

Data-URI au secours des performances

L'apport principal de data-URI se situe au niveau des performances de chargement des pages web. De nombreuses études lient directement le temps de chargement au taux de rebonds (ou d'abandon) des potentiels visiteurs. Ces études sont aujourd'hui encore plus réelles, compte tenu des connexions internet à bas débits via les appareils mobiles.

Réduction des requêtes HTTP

Un des facteurs clés de la performance d'un site est le nombre de requêtes HTTP qu'un navigateur doit faire pour être en mesure de l'afficher. C'est pourquoi les outils d'évaluation (comme YSlow et Page Speed) recommandent de réduire au maximum le nombre de requêtes. En voici quelques raisons :

  • Votre navigateur ne peut télécharger simultanément que quelques fichiers à la fois. Par défaut, le standard HTTP 1.1 suggère de limiter le nombre de requêtes simultanées à 2. La majorité des navigateurs actuels (et à partir de la version 8 d'Internet Explorer) en permettent en moyenne 6. Ce faisant, chaque ressource supplémentaire doit attendre qu'une connexion soit libre pour pouvoir être à son tour traitée. Les pages sont de plus en plus lourdes, font appel à de plus en plus de fichiers externes et la file d'attente s'allonge d'autant !
  • Chaque nouvelle requête doit se rendre au serveur et revenir, le temps de cette opération est appellée la latence (ou parfois roundtrip en anglais). Ainsi, à chaque nouvelle requête vous devez ajouter le temps de latence et le temps de traitement par le serveur au temps de téléchargement. Le temps de cette opération sera particulièrement élevé sur mobile, et parfois il arrivera qu'une requête se perde et doive être relancée.

En utilisant le schéma data-URI, plusieurs ressources sont regroupées dans un même fichier, et livrées ensemble sans nécessiter de nouvelle requête. Par exemple, une feuille de styles contenant 3 images d'arrière-plan incorporée à l'aide de data-URI n'exigera qu'une seule requête vers le serveur plutôt que 4. Dans ce même exemple, ces 3 images seront utilisables dès le téléchargement de la feuille de styles. Sans data-URI, ce n'est qu'après avoir reçu la feuille CSS que l'on pourra lancer le téléchargement de ces trois images (car celles-ci ne sont référencés qu'au sein de celle-ci).

Data-URI pourrait également sauver d'une utilisation fastidieuse des sprites CSS car les images pourraient être directement dans la feuille de styles. Ainsi, il sera inutile de regrouper les images en une seule pour réduire le nombre de requêtes serveur.

Garre aux excès

Cependant, il faut prendre bien garde aux excès qui pourraient, contre votre volonté, ralentir votre site. Ainsi, il ne faut jamais oublier que :

  • Les ressources identifiées par data-URI se retrouvent partie intégrante du fichier dans lequel elles se trouvent. Ce faisant, elles seront mise en cache avec leur fichier parent. Il ne serait donc pas judicieux d'intégrer des éléments data-URI au sein d'un fichier dont la mise en cache n'est pas permise à long terme par votre serveur (comme des fichiers HTML ou PHP).
  • Comme un data-URI est intégré directement, il ajoute du poids au fichier au sein duquel il se trouve chaque fois qu'il est inscrit. Ainsi, il faut veiller à n'inclure qu'une seule fois chaque ressource data-URI au sein de vos fichiers. Ainsi, vous éviterez d'ajouter un poids inutile à votre fichier.

    En CSS, il sera intéressant d'utiliser une class pour réutiliser une image sur différents éléments HTML.

  • Finalement, comme l'encodage base64 ajoute environ 10% au poids total d'un fichier. Si on fait un calcul simple, 10% de 100 octets est abordable, mais l'ajout de 10% de 200 Ko est plus considérable en terme de poids. Ce faisant, il n'est pas recommandé d'utiliser data-URI pour des fichiers pesant plus de 4 Ko; en dessous, aucun problème. (4 Ko est environ l'équivalent d'une requête HTTP supplémentaire)

Support des navigateurs

Bonne nouvelle ! Data-URI est supporté à partir d'Internet Explorer 8, Opera 7, et depuis toujours dans tous les autres navigateurs. Si vous suivez la règle de n'encoder que des fichiers en dessous de 4 Ko, vous n'aurez jamais de problème. Mais notez quand même qu'Internet Explorer limite la taille d'un data-URI à 32 Ko. Au-delà, il sera ignoré. Modernizr peut détecter le support de data-URI (url-data-uri dans la section "community add-on"). Mais vu le support plus que complet de ce schéma d'URI sur les différents navigateurs, se fier aux commentaires conditionnels suffit amplement.

Générer vos Data-URI

Comme vous êtes désormais des experts, il ne vous reste plus qu'à générer vos propres data-URI.

Outil en ligne

La solution la plus simple sera évidemment de les encoder via un outil en ligne : Dataurl.net vous permet de glisser/déposer vos fichiers et aussi d'encoder à la volée toutes les images présentes dans une feuille de styles si le site est en ligne. Il sera évidemment possible de définir le poids maximum des images à encoder dans les options.

DataURL

Encodage maison

PHP

Vous souhaiteriez générer vous mêmes vos data-URI ? Voilà ce que ça pourrait donner en PHP:

<?php

function dataURI_encode($file) {
  // argument devant être un chemin vers le fichier à encoder
  $mime_type = mime_content_type($file);
  $file_binary = file_get_contents($file);
  return 'data:' . $mime_type . ';base64,' . base64_encode( $file_binary );
}

?>
Javascript et Canvas

Javascript et le nouvel élément Canvas permettent également d'encoder une image en data-URI. Ceci pourrait par exemple vous permettre de conserver une image au sein de localStorage, méthode de stockage faisant partie de l'API Web Storage.

// imgReference est le noeud DOM d'une balise img
var getDataURI = function (imgReference) {
  var canvas    = document.createElement("canvas"),
    context   = canvas.getContext("2d"),
    extension = imgReference.src.split(".").pop().toLowerCase()
  ;

  // Donnons la même largeur et hauteur à notre élément canvas
  canvas.width  = imgReference.width;
  canvas.height = imgReference.height;

  // Nous dessinons notre image au sein de l'élément canvas
  context.drawImage(imgReference, 0, 0, imgReference.width, imgReference.height);

  // Nous retournons notre élément en tant que data-URI
  return canvas.toDataURL("image/" + extension);
}

// utilisation
var imgDataURI = getDataURI( document.getElementById('monImage') );
SASS et Compass

Le préprocesseur de feuille de style SASS permet grâce à son extension Compass de générer facilement des data-URI à partir d'images (ou de polices de caractères).

Pour ceci, rien de plus simple, il vous suffit d'appeller la fonction inline-image() :

selecteur {
  background-image: url( inline-image(../img/bullet.png) );
}

Ressources

Commentaires

A noter (car j'ai déjà entendu cette bêtise), le mode de compatibilité depuis un IE8 affiche les data-URI, mais ne croyez surtout pas une seconde que c'est supporté sur IE7 et inférieurs.

Merci pour cet article, néanmoins un petit pinaillage autour de la phrase : "Base64 est un type d'encodage (comme md5, sha1, etc)" : dans la mesure où le terme 'encodage' est utilisé ici dans le sens 'appliquer un codage de caractères', md5 et sha1 (deux algorithmes de calcul d'un condensat cryptographique) sont mal choisis ici car irréversibles ; il aurait mieux valu évoquer, par exemple, UTF-8, UCS-2, Unicode, ASCII, etc.

Merci pour cette article, mais pouvez-vous me dire si je me trompe en disant :

Encoder les images inférieures à 4ko appelées dans la feuille de style, permet de réduire le temps total de chargement, mais en contre partie la feuille de style sera plus lourde. Comme le navigateur ne commence à construire sa page que quand tous les éléments du head sont chargés, l’internaute aura pendant un instant plus long une page blanche. En dépit d’un meilleur temps total de chargement, l’expérience utilisateur sera moins bonne.