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
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.
-
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 étanttext/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 :
(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
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.
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
- http://en.wikipedia.org/wiki/Data_URI_scheme
- http://dataurl.net/#about
- http://draeton.github.com/stitches/
- http://en.wikipedia.org/wiki/URI
- http://calendar.perfplanet.com/2011/why-inlining-everything-is-not-the-answer/
- http://css-tricks.com/data-uris/
- http://ie7nomore.com/fun/data-uri/
- http://www.sitepoint.com/why-the-data-uri-scheme-could-help-save-your-slow-site/
- http://hacks.mozilla.org/2012/02/saving-images-and-files-in-localstorage/
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 ce tutorial !
Il me semble que l'on écrit abréviation avec un seul b ;)
Merci, la fonction va bien m'aider ;) !
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.
Bonjour,
trés interessant.
Apparemment le forum accepte ce type de lien.
Une bonne alternative aux personnes qui ne souhaite pas lier directement une page vers leur site professionnel ou celui de leur client.
Personnellement je me sert de http://bran.name/dump/data-uri-generator/ qui... permet d'encoder plusieurs fichiers d'un coup. :)
Un article qui manquait sur Alsa, merci beaucoup !
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.
Merci pour l'article, il a l'air très complet.
Petit complément, on peux utiliser des data-uri sous IE6-7, avec la syntaxe MHTML : http://www.phpied.com/data-uris-mhtml-ie7-win...
Dans la pratique, c'est une telle lutte à mettre en place que je me demande si ça en vaut la peine, mais ça reste bon à savoir.