21

Encodage d’images en Base64 et vitesse de chargement

Suite à l'article de Daniel Roch sur les différentes manières pour optimiser les performances d’un thème WordPress , je voulais rajouter mon petit grain de sel sur une optimisation parfois très efficace concernant les images. Cette astuce consiste à encoder les images en Base64.
Mais c'est quoi ce "Base 64" Aymeric? Pour ceux qui ne connaissent pas et si l'on s'en tient à la définition de Wikipédia, "base64 est un codage de l'information utilisant 64 caractères, choisis pour être disponibles sur la majorité des systèmes." Nous allons utiliser ce codage pour représenter des données binaires dans du texte. Je vous ai perdu? déja? Bon, fin de l'intro...

Un fichier image absent du serveur

Pour vous expliquer les choses à ma manière et sans vous parler de 2×6 = 8+4 = 12 bits comme wikipédia, on envoie une chaîne de caractères en base64 à l'internaute via un schéma d'URI (Data URI, URI=Uniform Resource Identifier) dans la page HTML, cette chaîne est ensuite décodée par le navigateur pour afficher l'image. Plutôt que des paroles, cherchez plutôt l'URL de cette image:

Vous avez vu? il n'y en a pas. Et c'est là tout l'intérêt. Mais à qui cela profite? à l'internaute ou au serveur? "Les deux mon capitaine!"

Moins de requêtes mais plus d'octets

L'un des gros avantages de cette technique d'affichage pour les images réside dans le fait qu'elle limite le nombre de fichiers à télécharger par le navigateur et donc le nombre de requêtes ce qui se traduit par des temps de réponses sur le serveur Web en moins.

En cas de forte d'affluence sur votre blog (suite à la rédaction d'une revue du web par exemple), vous soulagerez votre serveur de quelques connexions de trop.
C'est aussi un plus du côté de l'internaute. Il faut savoir que les navigateurs ont une limite de quelques connexions simultanées par domaine. Moins il y aura de ressources à charger simultanément, plus les éléments se chargeront rapidement pour afficher la page. À priori tout cela est positif, mais il y a malgré tout quelques inconvénients...

1er problème, Internet Explorer: certains navigateurs comme IE5,IE6 et IE7 ne supportent pas l'encodage en Base64, ce qui représente encore une petite partie du gâteau.

2ème problème, le poids des pages: ces données images contenues sous la forme de texte au sein de votre code source vont gonfler la taille de votre page HTML. Pour l'image ci-dessus par exemple, on rajoute 8635 octets à la page (l'image JPG originale ne pèse que 6459 octets). Avec la compression Gzip activée sur le serveur, cela réduit quelque peu la taille de la page finale.
Mais si on utilise l'encodage des images en base64 pour une image récurrente entre plusieurs pages d'un site, on alourdit le poids de toutes les pages et cela ne devient plus tellement avantageux.

3ème problème, image non physique: comme l'image n'est pas physiquement sur votre serveur, vous allez devoir passer par un encodeur comme celui-ci : http://www.greywyvern.com/code/php/binary2base64. A chaque modification de votre image, vous devrez passer par un outil qui effectuera l'encodage. Pas très souple comme solution...

Utiliser l'encodage en Base64 à mon escient

D'après un test ultra complet sur les images en base64 vs fichiers binaires, il faudrait choisir pour une feuille de style accompagnée de 5 images entre 130.986 octets et 5 requêtes HTTP ou 133.615 octets en 1 requête HTTP.
Pour gagner en performance, on va réduire les temps de réponse, et avec des feuilles de styles qui seront mises en cache par la suite, on ne va pas télécharger chaque image en base 64 à chaque chargement de page. Pour implémenter les images sur votre site, voici les méthodes avec le Data URI scheme data:[<MIME-type>][;charset=<encoding>][;base64],<data>:

Pour le HTML:

<img src="data:image/png;base64,GerehZhmeZG8xdpHQ4rO66GnK+pWmycgDn3q00Di+g2G0uJmAXPPtUyqRQRpSZfh0eeKZROpXPINZusjVUGXriIxnyzhVXgLjrWaldlOFkZ9zdpEAqjkD6V0RMGYsknmSsx......">

Pour les CSS:

monheader{
background:url(data:image/png;base64,GerehZhmeZG8xdpHQ4rO66GnK+pWmycgDn3q00Di+g2G0uJmAXPPtUyqRQRpSZfh0eeKZROpXPINZusjVUGXriIxnyzhVXgLjrWaldlOFkZ9zdpEAqjkD6V0RMGYsknmSsx......);
}

Heureusement pour vous éviter de faire la gymnastique je modifie mon image, je l'encode en base64, PHP a créé pour vous une fonction bien pratique pour encoder en base 64 à la volée et qui s'intitule base64_encode().
Notre ligne précédente (sous réserve que l'on génère dynamiquement notre feuille de style via une règle Apache RewriteRule (.*).css /$1.php) donnera donc:

monheader{
background:url(data:image/gif;base64,<? base64_encode(file_get_contents('monimage.jpg'))?>;);
}

Et là, ça devient intéressant. Pour une feuille de style qui contient une vingtaine d'images, on va économiser pas mal de requêtes! ... C'est donc essentiellement dans les CSS que l'encodage en Base64 est pertinent, pour tout ce qui va concerner les décorations/habillage d'un site. N'oubliez pas que les sprites CSS existent aussi, mais bon le codage en base64, c'est vraiment un truc de geek:)

et Google Images?

Etant donné que les images n'existent que virtuellement via du texte, Googlebot-Image/1.0 ne va pas indexer ce type d'images. Cela n'a pas réellement d'impact si vous utiliser ce système pour vos feuilles de style. Par contre, cela peut s'avérer intéressant mais totalement illégal si vous volez du contenu image et que vous ne voulez pas vous faire repérer... A l'inverse, utiliser le codage en Base 64 pour des images que vous ne souhaitez pas retrouver dans l'index de Google Images est une bonne solution (et oui, Googlebot et le robots.txt ne font pas toujours bon ménage...)

Conclusion: L'encodage en base64 est utile pour les CSS. Et vous, avez vous déjà intégré vos images de cette manière?

21 commentaires

  1. Du coup est-ce que tu as fait un test de temps de chargement avant/après pour comparer les gains ? C’est de l’ordre du millième de seconde ou un peu plus ?

  2. Bonjour Aymeric,

    Je ne connais pas suffisamment ce type d’encodage des images en Base64. Déjà si cela ne fonctionne pas sur un navigateur comme IE 7, c’est un peu embêtant pour la clientèle.

    amicalement

  3. Merci beaucoup pour le lien.

    J’avoue que je n’avais pas du tout pensé à inclure cette optimisation, d’une part car cela ne m’était pas venu en tête et d’autre part car cela nuira au référencement du site qui utilisera cette méthode.

  4. Le problème de cette technique (outre l’indexation des images), c’est la réplication des images (dans le cas ou ont l’utilises pour les pages HTML et non dans la css).

    Par exemple si tu affiches des images retaillées pour tes pages de catégories et sur tes pages de tags de la même taille tu va te retrouver avec deux fois l’image dans tes pages webs.

    Si tu utilises un reverse proxy comme varnish, tu vas donc consommer deux fois la taille de l’image dans le cache du proxy.

    Je ne te parle pas des problèmes décaches que cela peut aussi engendré (trouver toutes les pages qui affichent telle image …)

    Plutôt que de chercher à optimiser wordpress ou vos pages, je vous conseillerai de vous tourner vers varnish pour ceux qui ont un serveur.

    Pour les autres la compression gzip des pages html et de bon headers http sont déjà un bon commencement.

    Outre le fait d’étaler ma science ton article est très pertinent 😉

  5. Enfin si on a une 20aine d’images dans le CSS pour du décoratif … Le mieux reste un bon vieu sprite CSS, plutôt que des images en base 64.

    J’ai personnellement déjà fait le test, et il y avait aucune comparaison possible, le sprite est largement plus rapide que plusieurs images en base 64. Surtout que je trouvais que sur mes vieux PC, l’affichage lagué un peu (des PC portables de 8/10 ans).

  6. Est ce que cela aut bien la peine – en termes de pur SEO – c’est la question que je me pose moi – est ce que le gain de temps dans le chargement va avoir un impact reel sur mon ranking … ma foi je ne suis pas bien sur – surtout si le poid final de ma page augmente lui de son coté.

  7. Il me semble que ça pose plusieurs problèmes par rapport aux sprites CSS :
    1: L’encodage base64 rend la chaîne de caractère initiale plus lourde de 33% (d’après la doc php)
    2: Ca empêche le chargement parallèle du CSS et des images impossible, le CSS étant dans le head, le chargement de la page est bloqué jusqu’à ce que le CSS entier ait été chargé alors qu’avec un sprite, la CSS est chargée rapidement, l’affichage du site s’effectue et l’image est chargée par après sans ralentir l’affichage du site

  8. C’est énorme cette technique, vraiment :))
    Les sprites, c’est cool, mais on ne peut pas tous faire avec.
    Par exemple, allez utiliser un sprite pour mettre une image en background repeat, bon courage.
    Et pour insérer une image directement dans le HTML, la aussi l’encodage en base 64 va être utile.
    Donc bon, je trouve que c’est plutôt pratique et je suis sûr que je l’utiliserai.

    Mais la meilleur solution, quand c’est possible, c’est de passer par de la CSS3 😉

  9. Très bon article Aymeric, qui me remémore notre discussion lors du SEO Campus. L’intérêt serait de bloquer l’indexation de certaines mentions légales présentes sur toutes les pages en utilisant une image qui n’existe pas. 😉

  10. L’inconvénient de cette technique, c’est de ne pas profiter pleinement de la mise en cache des fichiers statiques par apache. C’est à mon sens plus efficace d’utiliser le cache client des navigateurs pour ces fichiers afin d’économiser des ressources et de la bande passante.

  11. A noter que cette technique est assez avancée, qu’elle n’est pas intéressante sur les fichiers de taille trop importante (rester sous les 4ko quoiqu’il arrive), qu’elle s’applique aux images de rendu plutôt qu’au contenu et que dans la plupart des cas on lui préférera l’utilisation de sprites CSS.

    Enfin l’étude de données empirique réalisée par la team de Google derrière mod_pagespeed avait l’air de montrer que l’inlining de petites ressources n’avait pas un impact très intéressant sur les perfs (cf : le premier pdf slide 7 http://velocityconf.com/velocityeu/public/schedule/detail/21697).

  12. Pas mal cette idée d’encoder les images en base64 pour gagner en vitesse de chargement. Mais comme il est précisé dans l’article, cette méthode ne fonctionne pas sur tous les navigateurs et engendre quelques autres inconvénients. Il me semblerait donc que ce l’on gagne d’un côté, on le perd de l’autre. Ainsi je reste dubitatif

  13. C’est super ce truc, tu viens de m’aider à voler des photos, c’est pas bien :p

    Merci.

  14. Oui je suis pas sur que la complexité soit au rendez vous du gain. De plus pour moi base64 = hack notamment pour les thèmes WordPress donc dès que je vois du base64 mon poil se hérisse.

    N’en reste pas moins que je salue la recherche et que cela donne tout de même de bonnes idées.

  15. Oui, dans mes CSS, car SmartOptimizer utilise cette méthode lors de la compression des fichiers CSS.

  16. Ca y est, je prends enfin le temps de lire un Aymeric qui fait du SEO et qui n’est pas mon mari ! (@AymericJ, non, je ne fais que lire ici !)
    Une raison de plus pour faire basculer les clients à au moins IE8, en tous cas !! Et leur montrer que la vitesse de chargement joue un VRAI rôle ! (« Mais si, vous voyez bien ?!)

  17. Je vous conseille vivement de ne pas faire ce que dis ce post : c’est une grosse erreur…

    1 – Base64 est plus lourd qu’une image ~33% plus lourd comme dit au dessus, mais aussi le réencodage (ou lecture du CSS par le browser) qui prend un sérieux coup dans la face !

    2- Sérieux après ton tuto, vous vous retrouvez avec un CSS carrément illisible, ou bourré de commentaire pour deviner quoi est quoi … (donc plus lourd encore une fois)

    3- Pour optimiser il vaut (largement) mieux opter pour un serveur asynchrone (ex: Nginx) pour servir les fichier static (gain 50% au bas mot)

    Bref, n’utiliser jamais le base64 pour optimiser (ralentir) votre serveur.

    • Il ne faut pas oublier que PHP peut encoder une feuille de style css dynamiquement/à la volée. L’encodage en base64 est inutile pour les images d’habillage de sites.
      Par contre, pour une liste d’actus c’est très utile: les photos/thumbs ne seront vu qu’une fois par l’internaute, on évite pas mal de requêtes serveur.

      La base64 reste également utile pour passer sous le radar de Google Images et rester discret si vous êtes malhonnetes…

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *