Les articles de la catégorie « Observations »

La technique des « Fab Four » pour créer des e‑mails responsive sans media queries

Je pense avoir trouvé une nouvelle façon de créer des e‑mails responsive, sans media queries. La solution implique la fonction CSS calc(), et les trois propriétés width, min-width ou max-width.

Ou comme je me plais à les appeler une fois toutes réunies : les « Fab Four » (en CSS).

calc() & width & min-width & max-width.

Lire la suite

Outlook.com ne préfixe pas les classes correspondant à des noms de balises

Comme la plupart des webmails, Outlook.com ajoute un préfixe aux noms de classes de nos e‑mails. Ainsi, une classe test sera transformée en ecxtest. Il y a quelques mois, j’avais remarqué cependant que ce préfixage ne s’appliquait pas sur certains noms de classes, comme par exemple button, menu, label ou nav.

Dans la troisième édition de son excellentissime Email Development Newsletter, Julie Ng évoque également ce bug qu’elle a rencontré en utilisant des classes head, header ou footer. Il n’en a pas fallu plus pour que je fasse le rapprochement et comprenne ce qu’il se passe. Tous ces mots-clés ne sont pas des noms pris au hasard, mais des noms de balises HTML.

Ni une, ni deux, je suis allé récupéré la liste des éléments HTML sur MDN, et j’ai envoyé le test suivant sur Outlook.com.

<style type="text/css">
	.html, .base, .head, .link, .meta, .style, .title, .address, .article, .body, .footer, .header, .h1, .h2, .h3, .h4, .h5, .h6, .hgroup, .nav, .section, .blockquote, .dd, .div, .dl, .dt, .figcaption, .figure, .hr, .li, .main, .ol, .p, .pre, .ul, .a, .abbr, .b, .bdi, .bdo, .br, .cite, .code, .data, .dfn, .em, .i, .kbd, .mark, .q, .rp, .rt, .ruby, .s, .samp, .small, .span, .strong, .sub, .sup, .time, .u, .var, .wbr, .area, .audio, .img, .map, .track, .video, .embed, .iframe, .object, .param, .source, .canvas, .noscript, .script, .del, .ins, .caption, .col, .colgroup, .table, .tbody, .td, .tfoot, .th, .thead, .tr, .button, .datalist, .fieldset, .form, .input, .keygen, .label, .legend, .meter, .optgroup, .option, .output, .progress, .select, .textarea, .details, .dialog, .menu, .menuitem, .summary, .content, .decorator, .element, .shadow, .template, .acronym, .applet, .basefont, .big, .blink, .center, .dir, .frame, .frameset, .isindex, .listing, .noembed, .plaintext, .spacer, .strike, .tt, .xmp {
		padding:1em 1.5em;
		color:#fff;
		background:#2ecc40;
	}
</style>
<div class="html base head link meta style title address article body footer header h1 h2 h3 h4 h5 h6 hgroup nav section blockquote dd div dl dt figcaption figure hr li main ol p pre ul a abbr b bdi bdo br cite code data dfn em i kbd mark q rp rt ruby s samp small span strong sub sup time u var wbr area audio img map track video embed iframe object param source canvas noscript script del ins caption col colgroup table tbody td tfoot th thead tr button datalist fieldset form input keygen label legend meter optgroup option output progress select textarea details dialog menu menuitem summary content decorator element shadow template acronym applet basefont big blink center dir frame frameset isindex listing noembed plaintext spacer strike tt xmp"></div>

Ce code est transformé par le code suivant :

<style type="text/css">
	.ExternalClass .ecxhtml, .ExternalClass .ecxbase, .ExternalClass .ecxhead, .ExternalClass .ecxlink, .ExternalClass .ecxmeta, .ExternalClass .ecxstyle, .ExternalClass .ecxtitle, .ExternalClass .ecxaddress, .ExternalClass .ecxarticle, .ExternalClass .ecxbody, .ExternalClass .ecxfooter, .ExternalClass .ecxheader, .ExternalClass .ecxh1, .ExternalClass .ecxh2, .ExternalClass .ecxh3, .ExternalClass .ecxh4, .ExternalClass .ecxh5, .ExternalClass .ecxh6, .ExternalClass .ecxhgroup, .ExternalClass .ecxnav, .ExternalClass .ecxsection, .ExternalClass .ecxblockquote, .ExternalClass .ecxdd, .ExternalClass .ecxdiv, .ExternalClass .ecxdl, .ExternalClass .ecxdt, .ExternalClass .ecxfigcaption, .ExternalClass .ecxfigure, .ExternalClass .ecxhr, .ExternalClass .ecxli, .ExternalClass .ecxmain, .ExternalClass .ecxol, .ExternalClass .ecxp, .ExternalClass .ecxpre, .ExternalClass .ecxul, .ExternalClass .ecxa, .ExternalClass .ecxabbr, .ExternalClass .ecxb, .ExternalClass .ecxbdi, .ExternalClass .ecxbdo, .ExternalClass .ecxbr, .ExternalClass .ecxcite, .ExternalClass .ecxcode, .ExternalClass .ecxdata, .ExternalClass .ecxdfn, .ExternalClass .ecxem, .ExternalClass .ecxi, .ExternalClass .ecxkbd, .ExternalClass .ecxmark, .ExternalClass .ecxq, .ExternalClass .ecxrp, .ExternalClass .ecxrt, .ExternalClass .ecxruby, .ExternalClass .ecxs, .ExternalClass .ecxsamp, .ExternalClass .ecxsmall, .ExternalClass .ecxspan, .ExternalClass .ecxstrong, .ExternalClass .ecxsub, .ExternalClass .ecxsup, .ExternalClass .ecxtime, .ExternalClass .ecxu, .ExternalClass .ecxvar, .ExternalClass .ecxwbr, .ExternalClass .ecxarea, .ExternalClass .ecxaudio, .ExternalClass .ecximg, .ExternalClass .ecxmap, .ExternalClass .ecxtrack, .ExternalClass .ecxvideo, .ExternalClass .ecxembed, .ExternalClass .ecxiframe, .ExternalClass .ecxobject, .ExternalClass .ecxparam, .ExternalClass .ecxsource, .ExternalClass .ecxcanvas, .ExternalClass .ecxnoscript, .ExternalClass .ecxscript, .ExternalClass .ecxdel, .ExternalClass .ecxins, .ExternalClass .ecxcaption, .ExternalClass .ecxcol, .ExternalClass .ecxcolgroup, .ExternalClass .ecxtable, .ExternalClass .ecxtbody, .ExternalClass .ecxtd, .ExternalClass .ecxtfoot, .ExternalClass .ecxth, .ExternalClass .ecxthead, .ExternalClass .ecxtr, .ExternalClass .ecxbutton, .ExternalClass .ecxdatalist, .ExternalClass .ecxfieldset, .ExternalClass .ecxform, .ExternalClass .ecxinput, .ExternalClass .ecxkeygen, .ExternalClass .ecxlabel, .ExternalClass .ecxlegend, .ExternalClass .ecxmeter, .ExternalClass .ecxoptgroup, .ExternalClass .ecxoption, .ExternalClass .ecxoutput, .ExternalClass .ecxprogress, .ExternalClass .ecxselect, .ExternalClass .ecxtextarea, .ExternalClass .ecxdetails, .ExternalClass .ecxdialog, .ExternalClass .ecxmenu, .ExternalClass .ecxmenuitem, .ExternalClass .ecxsummary, .ExternalClass .ecxcontent, .ExternalClass .ecxdecorator, .ExternalClass .ecxelement, .ExternalClass .ecxshadow, .ExternalClass .ecxtemplate, .ExternalClass .ecxacronym, .ExternalClass .ecxapplet, .ExternalClass .ecxbasefont, .ExternalClass .ecxbig, .ExternalClass .ecxblink, .ExternalClass .ecxcenter, .ExternalClass .ecxdir, .ExternalClass .ecxframe, .ExternalClass .ecxframeset, .ExternalClass .ecxisindex, .ExternalClass .ecxlisting, .ExternalClass .ecxnoembed, .ExternalClass .ecxplaintext, .ExternalClass .ecxspacer, .ExternalClass .ecxtt, .ExternalClass .ecxxmp {
		padding:1em 1.5em;
		color:#fff;
		background:#2ecc40;
	}
</style>
<div class="html base head link meta style title address article body footer header h1 h2 h3 h4 h5 h6 hgroup nav section blockquote dd div dl dt figcaption figure hr li ecxmain ol p pre ul a abbr b bdi bdo br cite code ecxdata dfn em i kbd mark q rp rt ruby s samp small span strong sub sup time u var wbr area audio img map track video embed iframe object param source canvas noscript script del ins caption col colgroup table tbody td tfoot th thead tr button datalist fieldset form input keygen label legend meter optgroup option output progress select textarea details ecxdialog menu ecxmenuitem summary ecxcontent ecxdecorator ecxelement ecxshadow ecxtemplate acronym applet basefont big blink center dir frame frameset isindex listing ecxnoembed plaintext spacer strike tt xmp"></div>

Tous les sélecteurs CSS sont bien préfixés par .ExternalClass .ecx. Par contre, les noms de classe dans le code HTML ne sont eux pas préfixés par ecx, rendant le sélecteur précédent caduque. Seuls quelques noms d’éléments HTML semblent échapper à ce bug (comme main, data, dialog, menuitem, content, decorator, element, shadow, template and noembed).

Par précaution, il est donc plus prudent de ne jamais utiliser de nom de balise HTML comme nom de classe.

Orange remplace le mot « overflow » par « java‑script »

Le webmail desktop d’Orange remplace le mot « overflow » par « java‑script ». Pas juste la propriété overflow en CSS. Mais carrément le mot « overflow », peu importe où vous l’employez dans un e‑mail.

Ainsi le code suivant :

<style>
	h1 { overflow:auto; }
</style>
<div style="overflow:hidden;">
	<h1 style="overflow:visible;">
		Un e‑mail qui parle d'overflow.
	</h1>
</div>

…est transformé en :

<style>
	h1 { java-script:auto; }
</style>
<div style="java-script:hidden;">
	<h1 style="java-script:visible;">
		Un e‑mail qui parle d'java-script.
	</h1>
</div>

Cela concerne uniquement le webmail desktop d’Orange (et pas sur l’application iOS ou le webmail mobile par exemple). Et cela se produit même lorsque « overflow » est inclus dans un autre mot.

Ça doit être très perturbant de lire des e‑mails de Stack Overflow sur le webmail d’Orange.

Supprimer les marges de l’application mail d’Android 4.4

James White a fait des recherches poussées pour comprendre d’où venaient des marges ajoutées autour du corps d’un e-mail sur l’application mail par défaut d’Android 4.4.

Résultat : l’application englobe chaque e-mail d’un <div style="margin: 16px 0;"> et ajoute un margin variable sur le <body> calculé selon la densité de pixels de l’appareil utilisé.

Pour annuler tout ça, James suggère d’ajouter les styles suivants :

body { margin:0 !important; }
div[style*="margin: 16px 0"] { margin:0 !important; }

Super Mail Forward, un e‑mail transférable évolutif

Litmus a organisé un nouveau concours communautaire avec comme thème : « créer un e‑mail qui vaille le coup d’être transféré ». Pour participer, j’ai créé un e‑mail que j’ai appelé Super Mail Forward, un e‑mail transférable (entre les webmails de Gmail, Yahoo, Outlook.com et AOL) qui évolue à chaque transfert. C’est un fantastique exercice qui m’a permis d’apprendre et de mettre en pratique plein de choses spécifiques à ces webmails. Voici quelques détails.

Super Mail Forward

Lire la suite

Ne pas confondre client mail et fournisseur de services de messagerie

J’ai récemment eu l’angoisse de réaliser le routage d’un e‑mail via Mailchimp. À ma grande surprise, ce service d’envoi d’e‑mail ne propose aucune statistique sur les clients mails utilisés. Mais il indique par contre de surprenantes données sur les fournisseurs de services de messagerie. Ainsi dans l’exemple ci-dessous, je constate que 22 % des destinataires de mon e‑mail avaient une adresse @orange.fr.

Les statistiques données par Mailchimp

J’ai un peu du mal à comprendre l’intérêt de telles statistiques. Mais surtout, j’ai remarqué que ça créait chez certains une incompréhension, interprétant ces données comme les statistiques des webmails utilisés. Avoir une adresse @orange.fr ne signifie pas que je consulte mes mails avec le webmail d’Orange.

Le contre exemple le plus simple concerne l’utilisation d’applications mail. Je peux très bien configurer mon adresse @orange.fr dans l’application Mail sur mon iPad, dans Outlook 2013 sur mon PC, et dans la dernière version de l’application Gmail sur mon téléphone Android.

Ce qui est souvent moins connu, c’est que la plupart des webmails permettent eux aussi de lire des e‑mails d’un autre fournisseur de services de messagerie. C’est le cas par exemple de Gmail, Outlook.com, Yahoo, La Poste, Orange ou SFR. Ainsi, je peux très bien lire les messages de mon adresse Gmail sur le webmail de Yahoo, les messages de mon adresse Orange sur le webmail de SFR, etc.

Il est donc primordial de ne pas confondre client mail et fournisseur de services de messagerie.

Comment les webmails bloquent les images

Certains webmails et applications mail bloquent l’affichage des images par défaut. Campaign Monitor et Litmus ont déjà des articles très complets expliquant quand cela arrive. Mais je me suis toujours demandé comment les webmails bloquent les images des e-mails quand ils ne les affichent pas par défaut. Je me suis intéressé principalement au blocage des images appelées depuis une balise <img>. Et j’ai identifié deux écoles.

Lire la suite

Flexbox dans un e‑mail

Tous les webmails ou applications mails ne supportent pas les media queries. Afin de pouvoir adapter la mise en page d’un e‑mail du mobile au desktop, il est important de trouver des solutions techniques ne reposant pas sur leur utilisation. Et ça tombe bien, puisque le module de mise en page en boîte flexible (Flexbox) permet exactement ça. Flexbox se présente alors, en théorie, comme le prétendant parfait pour mettre en page des e‑mails. J’ai fait quelques tests pour vérifier si c’était aussi le cas en pratique.

Le principe de base de Flexbox est d’appliquer des propriétés sur un élément parent qui auront une répercussion sur ses enfants directs. Certaines propriétés s’appliquent alors sur le parent :

  • display:flex
  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

Et d’autres propriétés s’appliquent sur ses enfants :

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

Si vous n’êtes pas familier avec Flexbox, je vous invite à consulter ce guide complet chez CSS-Tricks ou cette présentation chez Alsacréations. Voici un exemple de grille d’images que j’ai utilisé pour faire mes tests.

Une grille d'images avec Flexbox

Si le support de Flexbox dans les navigateurs modernes est plutôt bon, son utilisation nécessite toujours l’utilisation de préfixes -webkit- (pour Safari 8 et moins) ou -ms- (pour IE 10). Ainsi, la principale propriété display:flex s’écrit :

display:-webkit-flex;
display:-ms-flexbox;
display:flex;

Certains webmails (comme Gmail ou Outlook.com sur mobile) ne supportant pas les balises <style>, il est de bon usage pour l’intégration d’un e‑mail d’appliquer les styles directement en ligne sur chaque balise avec l’attribut style. Il existe des tas d’outils pour faire ça automatiquement. Et c’est là où j’ai rencontré une première difficulté pour tester. Absolument tous les inliners que j’ai testé ne tiennent pas compte des multiples déclarations de la propriété display et conservent uniquement la dernière. C’est le cas de Premailer, mais aussi des inliners de Mailchimp, Putsmail, Campaign Monitor ou encore Zurb. (Je n’utilise habituellement pas d’inliner automatique, et ce genre de cas particulier, ainsi que le fait que Premailer a actuellement 86 bugs en attente de correction sur Github depuis 2010, me confortent dans mon choix.) Voici la version avec les styles en ligne (ajustés à la main) que j’ai utilisé pour la suite de mes tests.

Et la bonne nouvelle, c’est que toutes les propriétés liées à Flexbox listées plus haut (et toutes leurs valeurs possibles) sont totalement supportées dans le webmails suivants :

  • Orange
  • SFR
  • Free (Zimbra)
  • AOL
  • La Poste

Cependant, mon exemple de grille d’images ne fonctionne pas pour autant avec La Poste. Mon code HTML ressemble à ça :

<div style="display:flex; flex-wrap:wrap;">
	<a style="flex:1 1 auto;" href="https://flic.kr/p/9sT8ev"><img src="bed2bb71f0.jpg" alt="" /></a>
	<a style="flex:1 1 auto;" href="https://flic.kr/p/npQD9i"><img src="c16031076e.jpg" alt="" /></a>
</div>

Problème : le webmail de La Poste entoure automatiquement chaque <a> par un <span>. Le code HTML précédent est alors transformé en :

<div style="display:flex; flex-wrap:wrap;">
	<span class="Object" id="OBJ_PREFIX_DWT100_com_zimbra_url">
		<a style="flex:1 1 auto;" href="https://flic.kr/p/9sT8ev"><img src="bed2bb71f0.jpg" alt="" /></a>
	</span>
	<span class="Object" id="OBJ_PREFIX_DWT101_com_zimbra_url">
		<a style="flex:1 1 auto;" href="https://flic.kr/p/npQD9i"><img src="c16031076e.jpg" alt="" /></a>
	</span>
</div>

La mise en page en flex ne s’applique alors plus sur les <a> mais sur les <span>. Ce problème peut être contourné en appliquant la propriété flex sur une autre balise qu’un <a>. Mais ça met en lumière un problème potentiel important : la moindre modification de code HTML risque d’avoir des effets secondaires indésirables importants.

Voici maintenant les webmails dans lesquels Flexbox n’est pas supporté :

  • Yahoo
  • Gmail
  • Outlook.com

Yahoo supprime purement et simplement toutes les propriétés liées à Flexbox listées ci-dessus, même la propriété display:flex.

Gmail et Outlook.com suppriment toutes les propriétés liées à Flexbox, sauf la propriété display:flex. Et dans mon exemple, ça pose du coup un gros problème, car la mise en page est quand même activée, mais avec les valeurs par défaut. Ainsi, sans flex-wrap, le retour à la ligne des images ne se fait plus, et le rendu est alors désastreux. Voici par exemple le rendu dans Outlook.com sur Firefox.

Le rendu de Flexbox sur Outlook.com dans Firefox

Mais Outlook.com a une autre dernière particularité. Il filtre toutes les propriétés liées à Flexbox sauf… celles préfixées par -ms-. Flexbox fonctionne alors très bien dans Outlook.com, mais que sur Internet Explorer 10 ou 11. Voici par exemple le rendu du même e-mail dans Outlook.com sur IE11.

Le rendu de Flexbox sur Outlook.com dans IE11

Côté applications, Flexbox fonctionne bien sur Apple Mail (sur OS X ou iOS), l’application Mail d’Android 4.4 et moins, Thunderbird 31 et plus. Voici un exemple de test de mon e-mail sur Email on Acid.

En conclusion, je dirais que Flexbox dans un e-mail pose malheureusement plus de problèmes qu’il n’aide à en résoudre. Je pense que ça peut être intéressant à utiliser, mais uniquement pour des problèmes qui ne peuvent pas être résolus autrement. Par exemple, la propriété order permet de réordonner les éléments, indifféremment de leur ordre dans le code HTML. iOS 9 va enfin supporter les déclarations @supports en CSS. On pourra alors écrire le code suivant :

@supports(order) {
	.block-to-reorder {
		order:1;
	}
}

De quoi faire un peu d’amélioration progressive, en attendant un meilleur support…

Le webmail mobile d’Orange et les double tirets

J’ai découvert tout récemment qu’il existait une version mobile du webmail d’Orange. Celle-ci semble utiliser le même préfixage de règles CSS que son pendant desktop, avec le même support de propriétés CSS (ce qui est plutôt une bonne nouvelle puisqu’Orange est plutôt permissif de ce côté là).

Cependant, j’ai remarqué un gros problème au niveau de l’interprétation de double tirets dans le code HTML ou CSS. Le webmail mobile d’Orange va systématiquement remplacer toute occurrence de -- (tiret tiret) par - - (tiret espace tiret). Et ça, c’est très pénible, en particulier si comme moi vous appréciez la notation de la méthodologie BEM. Prenons par exemple le code suivant…

<style>
	.button--primary { color:#fff; background:#333; }
</style>
<a class="button--primary" href="http://www.hteumeuleu.fr/">Mon blog</a>

…sera transformé par le webmail mobile d’Orange en…

<style>
	.button- -primary { color:#fff; background:#333; }
</style>
<a class="button- -primary" href="http://www.hteumeuleu.fr/">Mon blog</a>

La règle CSS .button- -primary n’a alors plus aucun sens, et ses styles sont ignorés par le navigateur. La solution est alors de ne jamais utiliser de double tirets dans un nom de classe HTML ou une règle CSS. Soit.

Mais ce problème touche également les commentaires HTML. Ainsi le commentaire suivant…

<!-- Ceci est un commentaire HTML -->

…sera transformé par le webmail mobile d’Orange en…

<!--- - Ceci est un commentaire HTML - --->

Par chance, les balises ouvrantes et fermantes du commentaire HTML sont quand même conservés. Mais ça se gâte si on utilise un commentaire conditionnel, par exemple pour cibler certaines versions d’Outlook. Ainsi le commentaire conditionnel suivant…

<!--[if gte mso 9]>Du contenu visible uniquement sur Outlook.<![endif]-->

…sera transformé par le webmail mobile d’Orange en…

<!--- -[if gte mso 9]-->Du contenu visible uniquement sur Outlook.<!--[endif]- --->

Le commentaire est ici carrément réécrit, avec une fermeture avec le [if gte mso 9], et une réouverture avant le [endif]. Ainsi, le contenu à l’intérieur du commentaire conditionnel, censé s’afficher uniquement sur Outlook, sera visible sur le webmail mobile d’Orange. Je n’ai alors malheureusement pas d’autre solution que de ne pas utiliser de commentaire conditionnel. Ou alors de choisir de ne pas supporter ce webmail mobile.

Un e-mail interactif avec filtre SVG et transitions CSS

Cette année, Litmus organise des concours communautaires visant à présenter des concepts d’e-mails un peu plus originaux que de trucs tout en tableaux. Le second concours vient de se terminer, et avait pour but de présenter une navigation créative au sein d’un e-mail. Pour participer, j’ai eu envie de porter cet effet de menu gluant créé par Lucas Bebber (et détaillé chez Codrops).

C’est un exemple particulièrement intéressant car cet effet nécessite à la fois l’utilisation d’un filtre SVG pour l’effet gluant à proprement parler, de transitions et transformations CSS pour faire bouger les éléments, et d’une interaction sans JavaScript. J’ai appris plein de choses en m’essayant à cet exercice. Voici le résultat final de ma participation et quelques détails sur le fonctionnement de tout ça.

Lire la suite