Pour comprendre flexbox en profondeur, Zoe Gillenwater transforme un layout préexistant créé avec table. Grâce aux media queries et aux possibilités d'ordonnancement de flexbox, ce layout devient encore plus responsif.
Par Zoe Gillenwater
Nous allons apprendre à utiliser flexbox pour fixer deux éléments à deux extrémités du viewport, avec un titre centré au milieu. Grâce aux media queries et aux possibilités d’ordonnancement de flexbox, nous pourrons rendre ce layout encore plus responsif.
Une bonne façon d’apprendre une nouvelle technologie est de prendre une chose créée avec les méthodes existantes et de le recréer avec les nouvelles méthodes. Philip Walton nous a montré dans ses démos “Solved by Flexbox” que flexbox nous permettait de créer beaucoup plus facilement beaucoup de choses qui étaient possibles mais laborieuses avec les méthodes CSS traditionnelles, tout en offrant plus de flexibilité aux contenus et aux scénarios utilisateurs. Je voudrais vous proposer un défi similaire : prendre un layout existant, et voir comment flexbox peut l’amener à un autre niveau.
Le design que nous allons convertir provient de l’article de Dan Mall sur son redesign du site de Crayola — et plus particulièrement les captures d’écran pleine page montrant comment le layout peut s’adapter, du plus petit au plus large.
Lorsque j’ai vu cet écran pleine page avec deux contenus épinglés de part et d’autre et un bloc au milieu, j’ai tout de suite pensé à justify-content:space-between
de flexbox, et j’ai décidé d’essayer de recréer ce layout avec flexbox. Attention, il n’y a rien d’erroné dans le design de Dan, c’est simplement un défi que je me suis lancé pour apprendre : comment pourrait-on faire différemment, et quels sont les avantages et les inconvénients de chaque méthode.
La version display:table
Dan utilise le positionnement absolu, donc pas besoin de me lancer là-dedans. Une autre option que je voulais comparer avec flexbox était la mise en page display:layout
, qui est souvent une bonne solution de repli pour les mises en page flexbox, surtout les layouts plein écran. Pour que display:table
fonctionne, il m’a fallu mettre la colonne la plus à gauche en premier dans mon HTML, puis la colonne du milieu, puis la dernière.
// html
<div class="layout-table">
<figure class="stretch-photo small">
<img src="img/flexbox_stretch_small.png" width="58" height="127" alt="mobile"/>
</figure>
<h2 class="stretch-title"><span>looks great from here to there</span></h2>
<figure class="stretch-photo big">
<img src="img/flexbox_stretch_big.png" width="361" height="294" alt="desktop"/>
</figure>
</div>
Cet ordre des sources n’est pas idéal car le texte du milieu est, d’un point de vue sémantique, un titre pour les deux images. Le résultat ne sera pas bon pour l’accessibilité, les utilisateurs de technologies comme les lecteurs d’écrans ne comprendront pas comment s’organise la page. C’est malheureusement souvent ce à quoi nous contraint la technique du display:table
. Mais si vous ne pouvez pas avoir un HTML parfait, au moins vous pouvez avoir un joli CSS !
//CSS
.layout-table {
display: table;
width: 100%;
}
.layout-table > * {
display: table-cell;
vertical-align: bottom;
}
.layout-table .stretch-title {
width: 100%;
padding-bottom: 4rem;
}
.layout-table .stretch-title span {
display: block;
border-bottom: 1px solid #ccc;
}
Ci-dessous, voici à quoi ressemble ma version table-layout. Je ne cherchais pas à reproduire à l’identique la version de Dan, simplement les éléments basiques de la mise en page. Vous remarquerez que dans ma version le texte est centré entre les deux images alors que dans celle de Dan il est centré par rapport aux blocs de texte au-dessus et en-dessous de lui. Ce n’est pas un avantage de l’une ou l’autre version, juste une différence, tout dépend du type d’alignement que vous souhaitez.
La version flexbox
À partir de ce point de comparaison, je me suis lancée d’abord dans la correction du problème d’ordre des sources.
//HTML
<div class="layout-flex-basic">
<h2 class="stretch-title">looks great from here to there</h2>
<figure class="stretch-photo small">
<img src="img/flexbox_stretch_small.png" width="58" height="127" alt="mobile"/>
</figure>
<figure class="stretch-photo big">
<img src="img/flexbox_stretch_big.png" width="361" height="294" alt="desktop"/>
</figure>
</div>
Si proche, et pourtant bien meilleur !
Pour utiliser flexbox sur ce beau HTML, on va utiliser display:flex
sur la div container des trois éléments ( NdT : n’oubliez pas d’utiliser Autoprefixer pour les préfixes constructeurs). J’utilise également align-items:flex-end
pour aligner verticalement les trois éléments, devenus des “flex items”, par le bas.
//CSS
.layout-flex-basic {
display: flex;
align-items: flex-end;
}
Mes trois morceaux sont bien alignés sur une rangée, mais bien sûr le titre vient en premier puisqu’il est le premier dans mon HTML. Je peux placer l’image du smartphone en premier en utilisant la propriété order
. Tous les items flex ont la propriété order
réglée sur 0 par défaut, donc -1 place l’image de smartphone avant les autres, et le titre se retrouve maintenant au milieu.
//CSS
.layout-flex-basic .small {
order: -1;
}
Il ne nous reste plus qu’à étirer le titre pour qu’il prenne toute la place sur la ligne, une fois que les images ont pris la leur. En fixant flex:1
, le problème est résolu. Je lui ai aussi donné un peu de margin-bottom
pour le faire remonter légèrement du bas, ainsi qu’une bordure pour créer la ligne qui va d’une image à l’autre.
//CSS
.layout-flex-basic .stretch-title {
flex: 1;
margin-bottom: 4.5rem;
border-bottom: 1px solid #ccc;
}
Et voilà ! Pas mal, non ? À part le problème des variantes navigateurs, qu’on peut résoudre avec Sass ou d’autres outils (Autoprefixer), c’est vraiment aussi simple qu’avec la version display:table
. Le résultat est le même, mais il est accessible et l’ordre des sources est sémantique.
L’avantage d’avoir un bon ordre des sources est que je peux facilement changer le layout sur des écrans de taille réduite afin d’avoir le titre en haut, dans sa position “naturelle”, avec les deux images empilées en-dessous. Ou bien je peux au contraire le placer sous les deux images :
//CSS
@media screen and (max-width:50em) {
.layout-flex-basic {
flex-wrap: wrap; /* permet d’avoir 2 rangées */
justify-content: space-between; /* déplace les images à chaque bout de leur rangée */
}
.layout-flex-basic .stretch-title {
flex: 1 0 100%; /* make it wrap to its own line */
order: 1; /* déplace au bout */
margin-bottom: 0;
margin-top: 1em;
border-bottom: none;
border-top: 1px solid #ccc;
}
.layout-flex-basic .small {
order: 0; /* revient à sa place normale */
}
}
C’est impossible de le faire avec la version display:table
. Je peux certes changer le CSS pour les écrans étroits, mais mon titre restera coincé entre les deux images dans mon HTML. L’ordre des sources est vraiment important.
Bien sûr, je peux aussi vouloir que le titre soit entre les deux images sur des écrans très réduits, et c’est très aisé à réaliser avec flexbox.
//CSS
@media screen and (max-width:480px) {
.layout-flex-basic {
flex-direction: column; /* empilement vertical */
flex-wrap: no-wrap; /* tout dans une seule colonne */
align-items: center; /* centré horizontalement */
}
.layout-flex-basic .stretch-title {
flex: 1 0 auto; /* affecte sa hauteur, pas sa largeur */
order: 0; /* revient à sa place normale */
width: 100%;
margin: 1em 0;
padding: .5em 0;
border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc;
}
.layout-flex-basic .small {
order: -1; /* placé au sommet */
}
}
Étendre la version flexbox
La version flexbox peut être étendue pour inclure bien des choses que nous n’avons pas dans la version display:table
. Je peux ajouter d’autres morceaux et les placer avec plus de précision et de flexibilité qu’avec display:table
. Admettons que je veuille ajouter une légende à chaque image, mais en les alignant sur le côté comme on le voit ci-dessous :
Voici le HTML logique :
//HTML
<div class="layout-flex-advanced">
<h2 class="stretch-title">looks great from here to there</h2>
<figure class="stretch-photo small">
<img src="img/flexbox_stretch_small.png" width="58" height="127" alt=""/>
<figcaption>mobile</figcaption>
</figure>
<figure class="stretch-photo big">
<img src="img/flexbox_stretch_big.png" width="361" height="294" alt=""/>
<figcaption>desktop</figcaption>
</figure>
</div>
Pour le réaliser avec flexbox, je transforme chaque <figure>
en un flex container. Ce sont toujours des flex items, de même que leur élément frère <h2>
, mais maintenant les éléments <img>
et <figcaption>
à l’intérieur de chaque <figure>
sont également des flex items. Cela signifie qu’ils peuvent être alignés de toutes les façons possibles.
//CSS
.layout-flex-advanced .stretch-photo {
display: flex;
align-items: flex-end;
}
Je veux que chaque légende <figcaption>
soit à côté de son parent <figure>
, donc j’ai besoin de coder “en dur” la largeur de chaque <figure>
(pas terrible, je sais) afin qu’elle ne s’étende pas en recouvrant sa légende. Je dois m’assurer que rien à l’intérieur de <figure>
ne soit flexible, et que tout reste à sa largeur native.
//CSS
.layout-flex-advanced img,
.layout-flex-advanced figcaption {
flex: 0 0 auto;
}
.layout-flex-advanced .small {
width: 58px;
}
.layout-flex-advanced .big {
width: 361px;
}
Chaque légende est en overflow de sa <figure>
, à droite, puisque le contenu va de gauche à droite.
Mais je peux changer cela, en utilisant le propriété flex-direction
. Vous savez sans doute qu’on peut utiliser flex-direction
pour passer d’une disposition row
à une disposition column
. mais ce ne sont pas les deux seules valeurs de flex-direction
, on peut aussi lui donner les valeurs column-reverse
et row-reverse
. Elles fonctionnent de la même façon que leurs alter ego column
et row
, mais font partir leur empilement dans la direction opposée à celle qu’on attend normalement. Donc, pour une langue écrite de gauche à droite comme le français, flex-direction:row
aurait pour effet de disposer les flex items de gauche à droite, mais flex-direction:row-reverse
les dispose de droite à gauche. C’est exactement ce que nous voulons pour notre grande image : placer l’image à droite de la rangée (premier dans l’ordre des sources), puis sa légende à sa gauche (deuxième dans l’ordre des sources).
//CSS
.layout-flex-advanced .big {
width: 361px;
flex-direction: row-reverse;
}
Et le problème est réglé.
Bien sûr, pour des largeurs d’écran réduites, nous pouvons placer les légendes à nouveau en-dessous de leur image — ou au-dessus, ou bien où nous le souhaitons, grâce à flexbox.
Le meilleur de tout est que flexbox peut être ajouté comme une amélioration progressive. Je pourrais utiliser le positionnement absolu comme l’a fait Dan, en tant que base, et ajouter par dessus ma construction flexbox, qui m’offre des options supplémentaites de placement et d’alignement que le positionnement absolu ne permet pas de réaliser.
Ce pattern “d’ici jusque là” peut aussi se retrouver dans une bannière principale ou juste dans une jolie photo montrant comment un bébé tout mignon est devenu grand :
Vous pouvez retrouver toutes les versions dans la page de démo et regarder le CSS. Comme toujours, redimensionnez la largeur de la fenêtre pour voir comment le layout s’ajuste aux différentes largeurs. Et bien entendu, utilisez un navigateur qui supporte flexbox ( NdT : c’est à dire aujourd’hui tous les bons navigateurs).
Intéressé par CSS ? Retrouvez une liste des meilleurs articles et ressources du web.
Retrouvez ici tous les articles sur Flexbox parus dans la Cascade.
(publicité)
Article original paru le 29 juillet 2014 dans le blog de Zoe Gillenwater Zomigi.
Sur l’auteur : Zoe Gillenwater est web designer et développeur, elle est spécialisée dans l’expérience utilisateur, le web design responsif et les techniques d’accessibilité. Ell est l’auteur de plusieurs ouvrages sur CSS et donne régulièrement des conférences à travers le monde. On peut la suivre sur son blog Zomigi, sur Google+ et sur Twitter.
Traduit avec l’aimable autorisation de Zomigi et de l’auteur.
Copyright Zomigi © 2014.