Le dernier bug d’Outlook.com (ou comment supprimer les marges sous les images)

Le mois dernier, Microsoft a introduit une nouvelle fonctionnalité dans Outlook.com et Office 365 qui a causé plein de problèmes aux intégrateurs et intégratrices d’e-mails. Il y a eu pas mal de discussions autour du sujet, que ce soit sur Slack ou les forums de Litmus. Ça m’a obsédé ces deux dernières semaines. Voici tout ce qu’il faut savoir sur ce bug et ma quête pour en trouver une solution.

La fonctionnalité

Si une image n’a pas de lien, Outlook.com la rends cliquable pour pouvoir afficher un écran d’aperçu. À partir de cet écran, vous pouvez naviguer entre toutes les autres images de cet e-mail.

Cliquer sur une image sans lien (ou sans Link en anglais) ouvre une fenêtre d’aperçu dans Outlook.com.

Je suis sûr que c’est une fonctionnalité intéressante si vous recevez un e-mail avec des photos de famille. Et ce genre de fonctionnalité n’est pas vraiment nouvelle dans le monde des webmails. Ça me fait penser aux « aperçus enrichis » de Yahoo ou aux icônes de téléchargement d’images de Gmail.

Malheureusement, l’implémentation de cette fonctionnalité par Microsoft est aussi mauvaise que possible.

Les bugs

Le bug le plus visible à cause de cette fonctionnalité est que chaque image a désormais une marge en dessous.

Des marges sont visibles (ici en rouge) sous les images découpées

Voir le code de cet exemple.

Afin de faire fonctionner tout ça, Outlook.com ajoute son propre code HTML autour de toutes les images. Prenons par exemple le code suivant pour une image.

<img src="botw.jpg" alt="" style="display:block; max-width:100%;" />

Voici le code après transformation par Outlook.com.

<div style="display: inline-block; max-width: 99.9%;">
 <button type="button" class="_at_6 o365button" aria-labelledby="_ariaId_107">
  <img src="botw.jpg" alt="" style="display:block; max-width:100%" />
  <span class="_fc_3 owaimg" style="display: none;"></span>
  <span class="_fc_4 o365buttonLabel" id="_ariaId_107" style="display: none;"></span>
 </button>
 </div>

Regardons de plus près ce qui se passe :

  1. Le webmail ajoute une <div> parent stylée en display:inline-block, alors même que mon image avait initialement un display:block. C’est ça qui cause l’apparition de marges (de la même manière que pour une <img> sur une page avec un doctype HTML5).
  2. La <div> parent a un max-width:99.9% appliqué. Cela n’arrive que si l’image a un max-width:100% (ce qui est assez courant pour un e-mail responsive). Selon la façon dont vous découpez vos images, ou si vous avez des couleurs de fond, cela peut créer des décalages bien visibles.
  3. Le webmail ajoute une balise <button> autour de l’image (avec deux <span> à l’intérieur également). Cela n’arrive que si l’image n’a pas de lien autour d’elle.

Différentes solutions ont été suggérées pour minimiser les effets de bord de ce code ajouté par Outlook.com, comme ajouter un font-size:0; sur un élément parent ou entourer chaque image avec une classe et réinitialiser les styles des éléments ajoutés par Outlook.com. Mais cela ne résout pas le problème du max-width:99.9%. Et je déteste l’idée qu’Outlook.com ajoute du code HTML au sein même de mes e-mails.

J’avais désormais un but précis : trouver le moyen d’éviter ça.

Et c’est ainsi que ma quête débuta.

L’enquête

Ma première idée a été de tester ce qui déclenchait cette fonctionnalité. J’ai donc commencé par faire plein de tests avec différentes imbrications de code pour comprendre quand est-ce que ça arrivait. Mais peu importe ce que j’essayais (comme déjà entourer l’image d’une <div> ou d’un <button>), Outlook.com ajoutait quand même son code.

Cependant, j’ai vite remarqué une chose : le max-width:99.9% n’était ajouté que lorsqu’il y avait un max-width:100% sur l’image. N’importe quelle autre valeur de max-width (comme 99%, 100.0001% ou toute autre valeur en pixels) était saine et sauve.

Un autre truc amusant que j’ai remarqué est que bien qu’Outlook.com supprime plein d’attributs modernes sur les balises <img> (comme srcset ou sizes), il gardait l’ancêtre dynsrc. Si vous n’étiez pas dans les parages dans les années 2000, l’attribut dynsrc était un attribut propriétaire de Microsoft pour inclure des vidéos dans des pages web.

À ce stade je me suis dit que ce serait marrant de faire une petite quête annexe pour voir si j’arrivais à lire une vidéo dans Outlook.com sur un vieil Internet Explorer. Donc j’ai lancé une des machines virtuelles (merci Microsoft). Si jamais vous vous demandiez à quoi ressemble Outlook.com sur Internet Explorer 8, voici la réponse.

Outlook.com sur Internet Explorer 8

Sur IE8, seuls un minimum de styles apparaît dans Outlook.com. Et aucune image n’est affichée.

C’est à ce moment là que j’ai réalisé que j’étais un idiot parce que dynsrc est seulement supposé fonctionner d’Internet Explorer 4 à 6. Et n’ayant pas de versions de ces navigateurs sous la main, j’ai arrêté là mon détour.

Mais quelque chose a retenu mon attention. Sur IE8, il semble que le code lié aux aperçus d’images soit totalement absent. Pas de <div>, pas de <button> et pas de max-width:99.9%. Le reste des filtres et préfixages de styles était pourtant lui bien appliqué (comme l’ajout d’un x_ devant chaque nom de classe, ou la suppression de media queries).

J’ai trouvé ça très intéressant. Et c’est comme ça que m’est venu l’hypothèse que peut-être que toute cette fonctionnalité serait ajoutée en JavaScript (et non pas côté serveur). Ce serait vraiment génial, car si c’est fait en JavaScript, je peux trouver et lire le code source correspondant.

Mais comme tout le webmail tourne avec du JavaScript, je ne peux pas me contenter de désactiver JavaScript dans mon navigateur pour voir ce qu’il se passe. J’ai donc utilisé l’outil Timeline de Chrome pour essayer de voir ce qu’il se passait. En voici une vidéo en pleine action.

En remontant la timeline, je pouvais bel et bien voir le moment où les lignes apparaissaient sous chaque image. Mon hypothèse semblait donc correcte, et tout ça est fait en JavaScript. En suivant les indications de trace de la pile d’exécution de Chrome, j’ai pu voir que les fonctions exécutées à ce moment précis venaient d’un fichier nommé boot.worldwide.o.mouse.init.js.

En parcourant ce fichier long de 25 000 lignes, j’ai pu retrouver exactement les mêmes noms de classe (_fc_3 et _fc_4) que celles ajoutées autour des images par le webmail.

Je n’ai pas réussi pour autant à définir un point de rupture sur cette fonction. Et le reste du code étant « uglifié », je n’arrivais pas à comprendre ce qu’il se passait à une plus grande échelle.

Donc j’ai décidé de partir à la recherche du max-width:99.9%. Mon intuition était que ça venait surement du résultat d’un calcul mal arrondi en JavaScript. Donc j’ai plutôt cherché la propriété maxWidth dans tous les fichiers JavaScript. Ça a donné neuf résultats.

Les neuf résultats pour la recherche de maxWidth

Et c’est dans un fichier nommé microsoft.owa.core.attachments.js que j’ai trouvé ce que je cherchais.

L'endroit exact dans le code où est appliqué le max-width:99.9%

v: function() {
 this.a && (this.a.style.maxWidth === "100%" || this.a.style.maxWidth === "99.9%") && (this.z.style.maxWidth = "99.9%")
}

Cette ligne de code dit que si un élément a existe, et si cet élément a un max-width de 100% ou de 99.9%, alors on applique un max-width:99.9% sur un autre élément z. Et voilà. C’est exactement le comportement que j’observais initialement.

À partir de là, j’avais une ligne où m’accrocher. J’ai donc défini un point de rupture, et sauté de fonction en fonction pour voir si je trouvais quoi que ce soit d’intéressant. Et c’est alors (qu’après ce qui m’a semblé des heures mais en fait c’était probablement juste quelques minutes), je l’ai trouvé. Le saint graal. Dans un fichier nommé microsoft.owa.attachments.extendedattachmentwell.js.

Le saint graal. La ligne de code qui va bien.

if(!t.id.startsWith(“OWATemporaryImageDivContainer”) && t.parentNode) { … }

Cette ligne dit que si un élément t n’a pas un attribut id qui commence par OWATemporaryImageDivContainer, et si cet élément t a un élément parent, alors le reste du code est exécuté. Ce qui signifie que si un élément a un identifiant qui commence par OWATemporaryImageDivContainer, alors le reste du code sera ignoré.

J’ai donc testé ça dans mon exemple initial.

<img id="OWATemporaryImageDivContainer1" src="botw.jpg" alt="" style="display:block; max-width:100%;" />

Et ça fonctionne. Le code est laissé tel quel par Outlook.com. Aucune balise HTMl n’est rajoutée.

Et c’est ainsi que ma quête s’acheva.

La solution

Ajoutez un attribut id qui commence par OWATemporaryImageDivContainer sur toutes vos balises <img>. Un identifiant devant être unique, faites attention à bien incrémenter sa valeur pour chaque image ou adoptez une convention de nommage en conséquence.

Maintenant vous pouvez avoir un lien sur vos images sans rien casser.

Une image avec un lien. Et un Link. Cette blague marche bien mieux en anglais en fait.

Le mot de la fin

J’ai passé plus d’une dizaine d’heures à rechercher tout ça. C’est plus de temps qu’il ne m’a fallu pour faire une expérience marrant d’e-mail transférable. C’est près de deux jours de travail non rémunéré pour contrer des mauvaises pratiques de Microsoft.

Dix ans après avoir choisi Word comme moteur de rendu pour Outlook 2007, et presqu’un an après un partenariat soit disant historique avec Litmus, Microsoft continue de rendre la vie plus difficile pour toute l’industrie de l’e-mailing. Alors que d’autres clients mail (comme Yahoo, Gmail ou Apple Mail) ont fait d’énormes progrès positifs ces dernières années, Microsoft continue de rendre chaque version d’Outlook encore pire. (Et je ne parle même pas des dernières versions d’Outlook sur iOS ou Android.)

J’en suis à un point où j’hésite presque à publier ce genre d’article, de peur que Microsoft ne tente de mettre des choses à jours et fasse encore pire que mieux.

  1. Martin, le

    Voilà des heures que je cherchais une solution. Merci mille fois pour ton article ! ;)

  2. Aurélie, le

    Bonjour Rémi & merci pour cette découverte – j’ai eu le bug sur un de mes emails, et ce hack m’a sauvé ! Merci pour le partage !

  3. Valentine, le

    Merci Beaucoup à toi pour cette quête et ce partage !! Tu m’as épargné des heures de prises de tête en emailing vs outlook !!!

  4. Remi Grumeau, le

    Faudrait remplacer Link avec un lit.
    En ch’ti ça donne « un lit hein ». Mais c’est pareil, ça marche pas partout… :)

    En essayant de tourner le truc dans tous les sens avec du
    div[id*= »MessagePartBody »] button.o365button
    ou du
    td div
    vraiment pour le test

    rien a faire, il n’applique rien du tout. Comme si il virait les styles non utilisé avant de faire son micmac en JS (qui a pour but de pouvoir afficher les images en fullscreen, ce qui aurait pu être fait avec un pauvre click event sur les img…

  5. Remi Grumeau, le

    Pour ajouter à mon commentaire juste avant et en y ayant repensé deux secondes, le but me semble très clairement d’améliorer l’accessibilité, et permettre par l’utilisation du de passer d’image en image via la touche tab, et entrer pour afficher en plein écran.
    D’un coup, ça semble donc plutôt être pour le mieux, enfin au minimum aller dans le bon sens (contrairement au choix d’utiliser Word y’a 10 ans par ex…)

    En revanche, vu le faible % de gens que ça représente rapport à la gêne occasionnée, le proposer dans un email à tous et en option à activer me paraitrait plus indiqué…

Les commentaires sont modérés manuellement et soumis à un filtre anti-spam. Merci de respecter l'auteur de l'article, les autres participants à la discussion, et la langue française. Vous pouvez suivre les réponses par flux RSS.