Mustache.js et ICanHaz.js au secours de jQuery

=>SOURCE<=

1. jQuery sans les moustaches

Imaginons qu’on veuille afficher une liste de livres (titre, auteur) que l’on récupère sous forme d’objets Javascript. Voici le code Javascript/jQuery correspondant :

var book = { title: "Javascript: the Good Parts", author: "Douglas Crockford" };
$('#example').append('Title: <b>' + book.title + '</b><br/>Author: ' + book.author);

Et le résultat :

Title: Javascript: the Good Parts
Author: Douglas Crockford

Je ne sais pas vous mais cette ligne là, elle m’irrite un peu quand je la lis et encore plus quand je l’écris :

$('#example').append('Title: <b>' + book.title + '</b><br/>Author: ' + book.author);

Pleins de ' et de +, c’est facile de s’y perdre et surtout on mélange affichage et données. En Java, il existe de nombreux systèmes de templates pour mettre en oeuvre cette séparation : VelocityFreemarkerStringTemplate et j’en passe. Et bien en Javascript, il existe également des systèmes de template dont Mustache, que je trouve simple et pourtant très puissant. Alors faisons appel à Mustache.js et voyons comment on peut rendre l’exemple précédent plus sexy.

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Title: <b>{{title}}</b> <br/> Author: {{author}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts
Author: Douglas Crockford

Aaah fini les ' et + parasites ! On a maintenant une belle séparation entre le template et les données. On utilise Mustache.render qui prend en paramètre le template et notre objet de données data. Dans le template, il y a deux tags {{title}} et {{author}} qui vont être remplacés par les valeurs correspondantes de l’objet data lors de l’appel àMustache.render.

On peut faire donc une première observation, un template Mustache est composé de tags et un tag est délimité par des doubles accolades : les fameuses moustaches !

2. Les tags Mustache

Pour l’instant, nous n’avons vu qu’un type de tag {{name}} qui permet d’afficher la valeur de l’attribut name de votre objet de données. Dans le jargon Mustache, name est la clé du tag. Voici un petit listing des tags Mustache qui existent :

{{#name}}, la moustache de section

Ce tag va ouvrir ce que Mustache appelle une section. Cette section peut contenir du text/html ou des tags Mustache. Une section est fermée par un tag {{/name}}. Si l’attribut name existe dans votre objet de données et est non null, non vide, non undefined alors Mustache va interpréter cette section. Dans le cas contraire, la section n’est pas interprétée.

var data = {title: "Javascript: the Good Parts", author: ""};
var template = '{{#title}} Title: <b>{{title}}</b> {{/title}} {{#author}} ne sera pas affiché {{/author}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts

Si name est un array, alors Mustache va itérer sur cet array et interpréter la section autant de fois que nécessaire.

var data = { books: [ "Javascript: the Good Parts", "Clean Code" ] };
var template = '{{#books}}<li>{{.}}</li>{{/books}}';
var output = Mustache.render(template, data);
$('#example').append(output);
  • Javascript: the Good Parts
  • Clean Code

Notez l’utilisation de {{.}} afin d’afficher l’élément de l’array.

{{^name}}, la moustache inverse

C’est l’inverse du tag {{#name}}, c’est-à-dire que le body du tag ne sera interprété que si l’attribut name n’existe pas, est vide, null ou undefined dans votre objet de données. Exemple :

var data = { books: [ ] };
var template = '{{#books}}<li>{{.}}</li>{{/books}} {{^books}}Aucun livre{{/books}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Aucun livre

{{! comment}}, la moustache invisible

C’est le tag de commentaire. Tout ce qu’il y a entre les moustaches est ignorée.

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Le commentaire suivant ne sera pas affiché : {{! ne doit pas être affiché}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le commentaire suivant ne sera pas affiché :

{{> tag}}, la moustache partielle

Avec Mustache, il est possible de définir des templates partiels afin de décomposer des templates qui seraient trop verbeux ou des templates que vous récupérez de plusieurs sources.

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Title: <b>{{title}}</b> <br/>{{> tplAuthor}}';
var partials = { tplAuthor: 'Author: {{author}}' };
var output = Mustache.render(template, data, partials);
$('#example').append(output);

Title: Javascript: the Good Parts
Author: Douglas Crockford

3. Fonctions

Dans votre objet de données, vous n’êtes pas cantonnés à avoir uniquement des valeurs ou des arrays. Vous pouvez également définir des fonctions qui vont déterminer le texte à afficher. Exemple :

var i = 0;
var data = { currentdate: function() { return i++;} };
var template = '<li>{{currentdate}}</li>';
$('#example').append(Mustache.render(template, data));
$('#example').append(Mustache.render(template, data));
$('#example').append(Mustache.render(template, data));
  • 0
  • 1
  • 2

Ok j’avoue, ça c’était l’exemple facile avec les fonctions. On peut faire un poil plus évolué. Dans les exemples précédents avec les livres, on affiche le titre en gras. Imaginons qu’on veuille rendre paramétrable l’affichage de “Title”, donc au choix en gras, en italique ou ce que vous voulez. Il suffit de fournir une fonction qui va faire ça.

var data = {
  title: "Javascript: the Good Parts",
  titleDisplay: function() {
    return function(text, render) {
      return '<b>' + render(text) + '</b>';
    }
  }
};
var template = 'Title: {{#titleDisplay}} {{title}} {{/titleDisplay}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts

Mais maintenant si je veux afficher le titre en italique et l’entourer par des guillemets, on remplace le corps de la fonction par :

return '"<i>' + render(text) + '</i>"';

Title: “Javascript: the Good Parts

Donc celui qui fournit l’objet data peut maintenant personnaliser l’affichage du titre.

4. Template multi lignes

“T’es bien gentil Ludo, mais tes exemples sont simplistes, tes templates ne tiennent que sur une seule ligne. Tiens prend ce template là. C’est beaucoup moins beau du coup et on peut vite oublier un antislash…”

var template = 'Title: {{title}} <br/>\
Author: {{author}} <br/>\
Edition: {{edition}}';

Effectivement, ce n’est pas très sexy. Alors il y a une petite astuce. Il suffit de mettre le template dans une balise <script> de type text/html, de récupérer son contenu et de le passer à Mustache ! En exemple ça donne :

<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
Edition: {{edition}}
</script>

 

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford", edition: "O'Reilly"};
var template = $('#book').html();
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts
Author: Douglas Crockford
Edition: O’Reilly

Mais on peut faire encore mieux !

5. ICanHaz.js

ICanHaz.js est une petite librairie Javascript qui wrappe Mustache.js et qui reprend l’idée de définir ses templates dans des balises script de type text/html. Au chargement de la page, ICanHaz.js va rechercher tous les templates de la page, créer un cache contenant ces templates et une fonction pour chaque template. A l’utilisation, c’est encore plus simple que Mustache.js. Si on reprend l’exemple précédent, le javascript devient :

<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
Edition: {{edition}}
</script>

 

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford", edition: "O'Reilly"};
var output = ich.book(data);
$('#example').append(output);

ICanHaz.js fournit un objet ich et a créé une méthode book correspondant à l’id de la balise script. ICanHaz.js permet également de gérer les partials Mustache de manière élégante en indiquant un attribut à la balise script. Si on remplace la partie “edition” par un partial :

<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
{{> edition}}
</script>
<script id="edition" type="text/javascript">
Edition: {{edition}}
</script>

et l’appel à ich.book(data) reste le même !

Comme je vous le disais précédemment, ICanHaz.js gère un cache de templates et fournit donc des méthodes pour rajouter des templates dans le cache, nettoyer le cache ou recharger le cache.

Conclusion

Si, sur votre projet, vous utilisez jQuery et n’utilisez pas de système de template côté client, alors foncez ! Essayez Mustache.js et ICanHaz.js ! Le tout ne fait que 5,4ko minifié.
Ensuite, je voudrais donner quelques précisions sur Mustache.js. Mustache.js est en fait l’implémentation Javascript du système de template Mustache (sans le .js). En effet, il existe de nombreuses implémentations de Mustache, en Java, Ruby, Python, PHP, etc…
De plus, on dit souvent que Mustache est un système de template “logic-less”, car il n’y a pas de if, else ou autre, il n’y a que des tags, que des moustaches :}}

8 extensions Chrome pour les développeurs

la galerie d'extensions chrome propose plusieurs dizaines d'outils pour les
La galerie d’extensions Chrome propose plusieurs dizaines d’outils pour les développeurs. Nous en avons sélectionné huit dans ce dossier.© Montage JDN avec Google et Spectral-Design – Fotolia.com

 

Accès au code source dans le navigateur, test de performance, exécution du moteur de rendu d’IE… Tour d’horizon de huit extensions du navigateur de Google utiles pour le développement.

CSS3 : Transformations 2D

voir la source

 

La propriété CSS transform permet de manipuler un élément HTML sur les axes X et Y (horizontal et vertical) grâce à des fonctions diverses de transformation graphique. Il est donc possible de modifier l’apparence d’un élément grâce à un ensemble fonctions 2D :

Syntaxe

La syntaxe est simple d’emploi.

transform: function(value);

Il est souvent nécessaire d’utiliser les préfixes vendeurs (-webkit--moz-, etc.) devant la propriété transform pour utiliser les transformations 2D sur les versions actuelles et passées de navigateurs. Reportez-vous aux tableaux de compatibilité pour savoir ce qu’il en est des moteurs, et à partir de quelles versions.

Il est également possible d’effectuer des transformations combinées en espaçant les fonctions d’un simple caractère blanc.

transform : function1(value1) function2(value2) function3(value3);

La propriété transform-origin

Pour pouvoir appliquer des transformations, nous avons besoin de savoir quel est le point d’origine (d’ancrage) de la transformation. La propriété transform-origin définit ce point d’origine.

La valeur initiale de cette propriété est le centre de l’élément, ce qui équivaut à la notation :

transform-origin: 50% 50%;

Il est possible de changer cette valeur en utilisant un mot-clef de position (topright,bottomleft) suivi d’une valeur chiffrée dont l’unité peut varier (px%, etc.)

div {
   transform-origin: top 0 left 0;
   transform: scale(1.25);
}

Il s’agit là de la syntaxe proposée par le W3C. À l’heure actuelle (2012) aucun navigateur n’implémente cette syntaxe correctement. Cependant, il suffit de supprimer les mots-clefs de position pour obtenir des résultats sur tous les navigateurs récents (toujours à condition d’utiliser les préfixes vendeurs -webkit-,-moz-,-ms-,-o- selon les versions);

Quelques exemples de positionnements :

Point d’origine en haut à gauche

transform-origin: 0 0;

Point d’origine en bas à droite

transform-origin: 100% 100%;

Point d’origine en bas et centré

transform-origin: 50% 100%:

Voici quelques exemples en démonstration de transformations avec la fonction scale (cf. le détail plus loin) dont le point d’origine varie.

Démonstration

Les fonctions de la propriété transform

Une fois l’origine choisie, nous pouvons affecter des transformations à nos éléments avec la propriété transform.

La fonction translate

Elle permet d’effectuer une translation (un déplacement) de l’élément sur les axes X et Y.

Il n’y a ici aucune notion de flux, l’élément part de son emplacement courant, quel que soit le type de positionnement que vous lui aurez attribué.

transform: translate(x,y);

y est une valeur optionnelle équivalente à 0 si elle n’est pas renseignée. Les deux valeurs peuvent être négatives.

Démonstration

Les fonctions translateX et translateY

Ces fonctions permettent de réaliser une translation sur l’axe X (translateX) ou Y (translateY).

transform: translateX(value) translateY(value);

Si vous pensiez comme moi que ces fonctions permettent une modification de l’une des deux valeurs du vecteur initial, dans le cas par exemple où la transformation vient en écraser une autre, alors vous faites erreur. Essayez le code suivant pour comprendre :

div {
   transform: translate(20px, 35px);
}
div:hover {
   /* redéfinition de la valeur X ? */
   transform: translateX(20px);
}

En définissant uniquement translateX sur l’évènement :hovertranslateY est implicitement redéfini avec la valeur 0.

Démonstration

La fonction scale

Cette fonction permet d’agir sur l’échelle (les dimensions) de l’élément. La valeur initiale est 1, tandis que les valeurs supérieures à 1 créent un effet d’agrandissement, et les valeurs inférieures créent un effet de réduction.

transform: scale(x,y);

La valeur y est optionnelle et sera égale à la valeur de x si elle est non renseignée, par exemple pour un agrandissement d’un facteur 1.25 :

transform: scale(1.25);

Les valeurs de x et y peuvent être aussi négatives. Il est possible d’effectuer ce « zoom » sur tous les éléments a priori… mais ce n’est pas parce que vous pouvez le faire qu’il faut le faire. N’oubliez pas qu’une image agrandie pourra être floue ou mal interpolée selon sa résolution initiale et celle de l’écran de destination.

Démonstration

Les fonctions scaleX et scaleY

Sur le même principe que pour les fonctions dérivées de translate, ces deux fonctions permettent de définir indépendamment les valeurs x et y.

Si scaleX est uniquement renseigné, scaleY vaudra implicitement 1 (aucun effet de scaleen y donc), et inversement.

transform: scaleY(1.25);

Cette transformation va élargir l’élément ainsi que son contenu éventuel. Il suffit de regarder la démonstration suivante pour constater la transformation (prêtez attention au texte de l’encadré vert).

Démonstration

La fonction rotate

Il s’agit d’une des plus simples fonctions à comprendre. Comme son nom l’indique, elle permet d’effectuer une rotation de l’élément ciblé.

Cette rotation s’exprime en degrés (unité deg). et peut être négative et supérieure de manière absolue à 360. Ce dernier point n’a de réel intérêt que lors d’une animation d’un état à un autre afin de présenter, par exemple, une rotation de plusieurs tours d’un élément. Autrement, sans animation de la rotation, la valeur 380° équivaut visuellement à une rotation de 20°.

transform: rotate(5deg);

Attention cependant, le point d’origine de la transformation a son importance comme le présente la démonstration qui suit.

Démonstration

La fonction skew

Cette fonction permet d’obliquer la forme d’un élément. À ma grande surprise, la documentation du W3C ne parle que des fonctions skewX et skewY, et pour cause :

Important, transform: skew() is not supported anymore (spec and gecko). (But skewX an skewY are).

Attention : les navigateurs qui prennent en charge la fonction skew() font du zèle. Cette fonction n’est pas prévue par le W3C, et ne sera plus supportée (prochainement par Gecko), dans un avenir proche. Pour faire les choses correctement, utilisez les fonctions skewX et skewY.

Les fonction skewX et skewY

Il s’agit des fonctions dérivées de skew. Voici deux exemples de transformation en utilisant les deux fonctions. Vous aurez compris la syntaxe de base :

transform: skewX(15deg);

…ou en changeant les valeurs de X et Y :

transform: skewX(15deg) skewY(15deg);

Démonstration

La fonction « absolue » matrix

Cette fonction permet de réunir en une seule déclaration toutes les fonctions précédentes que nous avons vu ensemble sous la forme d’une matrice. Très concrètement, les détails ne seront pas abordés ici car ils font beaucoup plus appel à des notions mathématiques complexes que beaucoup d’entre nous ont mis de côté.

Exemple d’une transformation avec beaucoup de fonctions :

div {
    transform-origin: 0 0;
    transform: rotate(15deg) translateX(230px)  scale(1.5, 2.6) skew(220deg, -150deg) translateX(230px);
}

Équivaut à la matrice suivante :

div {
    transform-origin: 0 0;
    transform: matrix(1.06, 1.84, 0.54, 2.8, 466px, 482px);
}

Pour comprendre comment fonctionne tout ceci, lisez l’excellent article de Useragentman.com : The CSS3 matrix() Transform for the Mathematically Challenged. Sachez qu’il existe un éditeur en ligne qui vous permet de manipuler une boîte dans le but d’obtenir des coordonnées matricielles : www.useragentman.com/matrix/

Ordre des déclarations

La propriété transform accepte plusieurs fonctions les unes à la suite des autres, comme proposé précédemment. Cependant, l’ordre des fonctions a son importance.
En effet, les deux transformations suivantes n’ont pas le même résultat :

div {
    transform: scale(2) translate(20px, 20px);
}

et différent de :

div {
    transform: translate(20px, 20px) scale(2) ;
}

De la même manière :

div {
    transform: translate(40px, 40px) scale(2) ;
}

propose le même résultat que :

div {
    transform: scale(2) translate(20px, 20px);
}

En effet, les transformations se font dans l’ordre où elles sont déclarées, ainsi une translation de 20px est équivalente à 40px si un scale de 2 la précède. Vous me suivez ?
Attention donc à l’ordre de déclaration de ces fonctions.

Du transform sur tous les navigateurs

Internet Explorer possède son propre filtre pour effectuer des transformations. En plus dufiltre propriétaire « Matrix », le comportement des transformations est différent puisque IE va tenter de transformer l’élément en restant collé aux bords haut et gauche de la boîte originelle (représentée par le cadre en pointillés dans les démo de cet article).

L’outil IE TransformsTranslator permet de corriger le tir en appliquant automatiquement des marges aux éléments transformés pour IE.

Tableau des compatibilités

Navigateurs Versions Détails
Internet Explorer Internet Explorer 9+ Avant la version 9, il est possible d’utiliser les filtres propriétaires.
A partie de la 10 : sans préfixe -ms-.
Firefox Firefox 3.5+ à partir de 16.0 : sans préfixe -moz-
Chrome Chrome 4+
Chrome Mobile (Android 4)
avec préfixe -webkit- jusqu’à 23.0 (+ ?)
Opera Opera 10.5+
Opera Mobile 11+
à partir de 12.5 : sans préfixe -o- et 11.0 sans préfixe pour Opera Mobile
Safari Safari 3.1+
Safari Mobile (iOS 3.2)
avec préfixe -webkit-
Android Browser Android Browser 2.1+ avec préfixe -webkit-

 

Ressources

Adobe joue la carte HTML5 avec les outils Edge

voir la source

 

Adobe a décidé de donner un coup d’accélérateur vers le monde du web dans sa gamme d’outils, avec Edge Tools & Services. C’est un grand pas effectué en faveur de HTML5, des designers, développeurs et intégrateurs, qui ne disposaient jusqu’à présent que de peu de programmes avant-gardistes dans la Creative Suite pour exploiter les nouveaux modes de conception de sites et d’applications web. Par ailleurs, la plupart de ces services sont fournis à titre gratuit, par exemple Edge Animate qui sera mis à disposition via Creative Cloud dans un premier temps puis deviendra payant à part entière, ou intégré à la suite pour ceux qui disposent d’un abonnement.

On voit là l’intention de revenir dans la course après avoir essuyé des revers avec Flash, qui a décidément de plus en plus de mal à convaincre. L’acquisition de Tyepkit et PhoneGap étoffent les outils « maison ». Voici la collection :

Edge Animate

Pour créer des animations à l’aide de HTML/CSS/JavaScript, à l’aide d’une ligne de temps (timeline) ressemblant de très près à l’IDE Flash, symboles y compris. L’ensemble produit est destiné à s’afficher sur les navigateurs récents (mobiles sous iOS et Android, Firefox, Chrome, Safari, Internet Explorer 9) avec une alternative pour les plus anciens. Le mode d’aperçu lui-même est basé sur un moteur WebKit. Le code généré est stocké dans un fichier à part pour préserver l’intégrité de la page HTML initiale.

Adobe Edge Animate

Edge Reflow

Destiné à créer des mises en page qui s’adaptent aux contraintes de l’écran, Edge Reflow est la pierre angulaire de cette suite d’outils pour le Responsive Web Design. Il est possible de jouer dynamiquement avec les dimensions du document pour créer des points de rupture et définir de quelle façon le contenu doit se ré-arranger en fonction de la largeur autorisée. Il s’agit bien là d’exploiter la puissance des Media Queries CSS3. Voir la vidéo de présentation.

Adobe Edge Reflow

Edge Code

Initialiement basé sur le projet Brackets, Edge Code est voué à devenir un éditeur de code source puissant et personnalisable, étant lui-même construit sur HTML/CSS et JavaScript. Il voit l’intégration des autres services proposés par Adobe, notamment Web Fonts et PhoneGap Build, sans compter l’aperçu rapide des modifications CSS, la vue projet et la coloration syntaxique. Si vous pensiez que l’éditeur de Dreamweaver mériterait d’être allégé, voilà qui comble un besoin exprimé par beaucoup de développeurs auprès de l’éditeur.

Adobe Edge Code

Edge Inspect

Avec Edge Inspect, il est possible de tester le rendu graphique sur de multiples plate-formes avec une synchronisation des aperçus, mais aussi des outils pour inspecter le code ou les propriétés du document, les changer à la volée – même sur mobile – et constater en direct la conséquence des modifications. En bonus, des captures d’écran vers le disque local, rendues plus faciles par une intégration de cet outil sur tous les périphériques.

Adobe Edge Inspect

Les autres…

Venant compléter ces nouveautés, Edge Web Fonts a déjà été publié en tant qu’outil, pour intégrer des polices web (gratuitement) à l’instar de Google Web Fonts ; tandis que PhoneGap Build est axé vers les mobiles pour packager des applications HTML5 et les déployer vers les plate-formes les plus répandues actuellement : Android, iOS, Windows Phone, BlackBerry, webOS, Symbian.

À tester

Inspect, Reflow et Animate sont bien entendu les plus intéressants car ils répondent à des besoins désormais courants pour lesquels le paysage de logiciels disponibles est restreint. Beaucoup de fonctionnalités HTML5 et CSS3 sont encore développées « à la main », faute d’environnements intégrés produisant un code propre.

Cet ensemble est bien prometteur. Il vous faudra bien entendu de bonnes connaissances avant de pouvoir exploiter les fonctionnalités avec efficacité et connaître exactement ce que ces outils vont générer pour vous. Adobe souhaite attirer un maximum de créateurs de tous bords et les fidéliser dans son Creative Cloud. Si la famille Edge parvient à tenir ses promesses et à évoluer dans le temps pour suivre les innovations de près, tout en restant universelle, il y a de fortes chances que l’éditeur de logiciels tire son épingle du jeu face à tous les autres programmes qui existent déjà sur le web, libres ou payants.

CSS3 Flexbox Layout module

voir la source

 

Positionner correctement des éléments en CSS s’est toujours révélé être une mission aussi palpitante que fastidieuse en raison d’un lourd passé de navigateurs assez peu enclins à suivre des standards communs. Depuis sa création, CSS propose officiellement quatre types de rendus d’éléments :

  • Le rendu « bloc »
  • Le rendu « inline »
  • Le rendu « tabulaire »
  • Le rendu « positionné »

Chacune des valeurs de la propriété display (par exemple inline-block), de float, ou deposition, renvoie à l’un de ces quatre types de rendus.

CSS3 étend ce périmètre en introduisant un nouveau modèle de boîte « flexible » : Flexbox, ou Flexible Box Layout Module.

Flexbox est un nouveau mode de positionnement, introduit via la propriété display, permettant de créer un contexte général d’affichage sur un parent et d’en faire hériter ses enfants :

  • Distribution en bloc ou en ligne,
  • Alignements horizontaux et verticaux,
  • Gestion des espaces disponibles (fluidité à l’instar des cellules de tableau),
  • Réorganisation des éléments indépendamment de l’ordre du flux (DOM).

Compatibilité de Flexbox module

Commençons par calmer les plus optimistes d’entre vous et ceux que je vois déjà en train de se ruer sur leur éditeur HTML préféré. Posons d’entrée le décor ; j’ai deux bonnes et une mauvaise nouvelle :

  • La première bonne nouvelle est que les spécifications concernant Flexbox sont au stade de « Candidate Recommandation » et peuvent être aujourd’hui considérées comme stables.
  • La seconde bonne nouvelle est que l’implémentation de Flexbox sur les navigateurs est « relativement correcte », comme en témoigne l’excellente ressource Caniuse.
  • La mauvaise nouvelle est que les spécifications ont radicalement changé plusieurs fois et que les navigateurs compatibles sont susceptibles de reconnaître l’une ou l’autre des versions des spécifications, parfois de manière incomplète, et – bien entendu – avec moults préfixes de partout !

Malgré ces quelques petites embûches, consolez-vous en vous rappelant notamment que dans le monde du Web mobile, les navigateurs récents sont déjà parfaitement prêts à afficher vos sites web dans ce mode de positionnement avant-gardiste.

Tableau des compatibilités

Navigateurs Versions Détails
Internet Explorer Internet Explorer 10+
IE mobile 10+
Ancienne spécification. Avec préfixe -ms-
Firefox Firefox 2+ Ancienne spécification. Avec préfixe -moz-
Chrome Chrome 4+
Chrome Mobile (Android 4+)
Ancienne spécification depuis Chrome 4. Avec préfixe -webkit-
Spécification finale depuis Chrome 21. Avec préfixe -webkit-
Ancienne spécification pour Chrome sur Android. Avec préfixe -webkit-
Opera Opera 12.1+
Opera Mobile12.1+
Spécification finale. Sans préfixe
Safari Safari 3.1+
Safari Mobile (iOS 3.2+)
Ancienne spécification. Avec préfixe -webkit-
Android Browser Android Browser 2.1+ Ancienne spécification. Avec préfixe -webkit-

Des spécifications fluctantes

Comme vous l’avez judicieusement constaté à la lecture attentive du tableau de compatibilité, la spécification de Flexbox a connu différentes étapes de syntaxe et nommage. Il y a eu trois syntaxes très différentes au cours de l’évolution de ce module :

Syntaxe 2009 Syntaxe 2011 Syntaxe 2012 (finale)
display : box display : flexbox display : flex
box-flex flex flex
box-ordinal-group flex-order order
box-orient flex-direction flex-direction
box-pack + box-align flex-pack justify-content + align-items

Pour des raisons pratiques évidentes, nous nous contenterons des syntaxes standardisées et sans préfixes au sein de cet article, il vous incombera de rajouter tous les préfixes constructeurs si vous désirez appliquer les exemples de codes sur votre navigateur préféré.

Appliquer Flexbox

Le principe général de Flexbox peut paraître assez déroutant de prime abord, mais finalement très pratique : il suffit de créer un « contexte de boîte flexible » sur un parent à l’aide de la propriété display afin qu’il soit appliqué à l’ensemble de ses enfants directs.

Tout au long de cet article et pour l’ensemble des exemples pratiques, nous avons choisi le navigateur Google Chrome, actuellement le plus à même de supporter cette spécification dans sa dernière version stable. Cependant, rien ne devrait vous empêcher de tester sur d’autres navigateurs.

En clair, la règle suivante va affecter les éléments enfants de .kiwi :

.kiwi {display: flex;}

flex01

Démonstration display: flex

Modifier l’orientation

L’un des premiers avantages de ce type de positionnement est de pouvoir jongler aisément entre une disposition d’éléments sous forme de colonnes (blocs) ou de lignes (inlines).

Pour ce faire, il suffit là encore d’indiquer ce comportement sur le parent à l’aide de la propriété flex-direction :

/* les enfants s'affichent en colonne */
.kiwi {flex-direction: column;} 

/* les enfants s'affichent en ligne */
.kiwi {flex-direction: row;} 

flex02

Démonstration flex-direction: column

Le suffixe -reverse inverse l’ordre d’affichage :

/* les enfants s'affichent en colonne inversée */
.kiwi {flex-direction: column-reverse;} 

/* les enfants s'affichent en ligne inversée */
.kiwi {flex-direction: row-reverse;} 

flex02b

Démonstration flex-direction: column-reverse

Dans la lignée de flex-direction, signalons l’existence de la propriété intéressante flex-wrap.

Cette propriété autorise (ou non) les éléments à s’afficher sur plusieurs lignes lorsqu’elles dépassent de leur conteneur, les valeurs étant les suivantes :

  • flex-wrap: nowrap : les éléments demeurent toujours sur une ligne, et peuvent déborder
  • flex-wrap: wrap : les éléments passent à la ligne plutôt que de déborder
  • flex-wrap: wrap-reverse : les éléments passent à la ligne… en inversant leur direction

flex03

Démonstration flex-wrap: wrap

flex03b

Démonstration flex-wrap: wrap-reverse

Pour votre culture personnelle, sachez qu’il existe une propriété raccourcie flex-flowqui regroupe flex-direction et flex-wrap.
Ne vous étonnez donc pas de rencontrer tantôt la syntaxe .kiwi {flex-flow: column;}

/* affichage en ligne et passage à la ligne autorisé */
.kiwi {flex-flow: row wrap;} 

Gérer les alignements horizontaux et verticaux

Flexbox propose de gérer très finement les alignements et centrages, en différenciant les deux axes d’affichage de cette manière :

  • Les alignements dans l’axe principal sont traités via la propriété justify-content et ses différentes valeurs : flex-startflex-endcenterspace-between et space-around
  • Les alignements dans l’axe secondaire sont gérés avec align-items et ses valeurs :flex-startflex-endcenterbaselinestretch

Exemple de centrage horizontal et vertical :

.kiwi {
  justify-content: center;
  align-items: center;
} 

flex04

Démonstration justify-content

flex05

Démonstration align-items

Alignement : gérer les exceptions

La propriété align-self offre la possibilité de distinguer un élément particulier de ses frères en adoptant un alignement différent.

Attention toutefois, cette méthode peut dans certains cas causer des soucis d’accessibilité lorsque la feuille de style est désactivée (Cf Accessiweb 2.2 critère 10.3).

.kiwi > li:last-child {
  align-self: flex-end;
} 

flex05b

Démonstration align-self

Autre astuce, la propriété margin et sa valeur auto permettent de positionner un élément en dehors de la distribution de ses frères.

Il devient donc possible d’afficher un groupe d’élément à gauche du parent et d’en placer un à droite :

.kiwi {
  justify-content: flex-start;
} 
.kiwi > li:last-child {
  margin-left: auto;
}

flex05c

Démonstration margin: auto

Jouer avec la flexibilité des éléments

Cela ne devrait étonner personne, la notion de flexibilité constitue le fondement du module de positionnement Flexbox, et c’est là qu’intervient l’indispensable propriété flex.

La propriété flex est un raccourci de trois propriétés, flex-growflex-shrink et flex-basis, dont les fonctions sont :

  • flex-grow : propension pour un élément à s’étirer dans l’espace restant
  • flex-shrink : propension pour un élément à se contracter si besoin
  • flex-basis : taille initiale de l’élément avant que l’espace restant ne soit distribué

Les particularités des propriétés de flexibilité étant assez nombreuses (et leursspécifications assez alambiquées), je vous propose un petit résumé explicatif simplifié :

Pour rendre un élément flexible, il suffit de lui attribuer une valeur de flex-grow (ouflex en raccourci) supérieure à zéro.
Cet élément occupera alors l’espace restant au sein de son conteneur :

/* .salade occupera l'espace restant */
.salade {
  flex: 1;
}

Plusieurs éléments peuvent être rendus flexibles et se répartir l’espace restant.

Dans l’exemple ci-dessous, l’espace total est découpé en 4 (1+2+1), puis partagé entre les trois éléments selon le « poids » attribué à chacun. En l’occurrence, le troisième occupera la moitié de l’espace (2/4), les deux autres se partageant le reste par parts égales.

.salade {
  flex: 1;
}   
.tomate {
  flex: 2;
}   
.oignons {
  flex: 1;
}

En ajoutant une valeur supplémentaire, celle de flex-basis, il est possible d’indiquer une largeur minimale préférée qui sera appliquée tant qu’il n’y a pas d’espace superflu :

.salade {
  flex: 1 200px;
}   
.tomate {
  flex: 2 400px;
}   
.oignons {
  flex: 1 200px;
}

flex06

Démonstration flex n°1

flex06b

Démonstration flex n°2

Gabarit flexible

Réordonner les éléments au sein de leur parent

L’une des fonctionnalités les plus avant-gardistes du modèle d’affichage Flexbox est de pouvoir réordonner à sa guise chacun des éléments indépendamment grâce à la propriétéorder.

Les valeurs de order agissent telles des pondérations : les éléments dont la valeur est la plus forte se trouveront en bas de la pile. La valeur initiale de order est 0.

/* le premier de la liste s'affichera en bas de pile */
li:first-child {
  order: 1;
}

flex07

Démonstration order

Démonstration navigation

Pour aller plus loin

Voici quelques ressources externes pour en savoir plus sur ce positionnement très polyvalent :

Articles et tutoriels connexes

Alternatives

Il existe un outil de type polyfill en JavaScript afin d’émuler le support de Flexbox sur les anciens navigateurs tels IE6-IE9 et Opera 10. Il s’agit de Flexie.js. Vous pouvez le tester surFlexie Playground. Sachez cependant que cette alternative JavaScript ne semble plus mise à jour depuis une bonne année et se base sur la syntaxe désuette de 2009.

Signalons également l’existence d’un outil de test de Flexbox en ligne : Flexplorer (à tester sur un navigateur compatible).

Conclusion

Flexbox est une spécification vaste et complexe, nous n’en n’avons démontré que les parties les plus exploitables mais d’autres recoins restent à explorer et seront dévoilés au fur et à mesure de leur support avec les navigateurs. Quoi qu’il en soit, le positionnement Flexible Layout regroupe de nombreuses bonnes pratiques et attentes des webdesigners et intégrateurs depuis de longues années. Dans un avenir proche (ou dès maintenant selon votre cible), il constitue sans aucun doute la méthode de positionnement la plus pratique et polyvalente.