Ce tutoriel a pour but de présenter dans les détails une technique de conception de grille de mise en forme responsive à l’aide du positionnement CSS3 Flexbox Layout, actuellement parfaitement adapté à ce genre de fonctions en attendant une meilleure implémentation de Grid Layout.
En février 2016 est sorti mon livre entièrement dédié à Flexbox. Il se nomme "CSS3 Flexbox : plongez dans les CSS modernes" et je vous recommande bien évidemment sa lecture afin de comprendre tous les rouages de ce positionnement révolutionnaire, et d'en maîtriser tous les aspects.
Le concept de grille produite permettra de gérer les espaces inter-colonnes (gouttières), les décalages (“offsets”), les différentes tailles d’écran et d’être automatisable. Le tout en un minimum de code et un maximum de propreté HTML.
Voir le résultat final en ligne
Le fondement : Flexbox Layout
Notre grille sera construite grâce au module Flexbox, aujourd’hui compatible sur une bonne majorité des navigateurs (95% en France selon les stats Caniuse en fin 2014).
Si vous souhaitez assurer un maximum de compatibilité envers les anciens navigateurs, vous devrez vous rabattre sur les techniques float
, table-cell
ou inline-block
avec tous les détails et exemples dans cet article consacré aux grilles de mise en forme.
Note : Flexbox nécessitant encore certaines précautions en terme de préfixes et de syntaxes, je vous conseille vivement de vous équiper de l’outil Autoprefixer afin de vous décharger de cette tâche fastidieuse une fois pour toutes.
Les bases de la grille
Mon souhait est que seul le conteneur sera affublé d’une classe, et ses enfants (directs) en bénéficieront automatiquement, sans avoir à les nommer spécifiquement.
Par exemple, le code imaginaire suivant pourrait générer une grille de 4 colonnes où tous les enfants directs occuperaient 1/4 de l’espace disponible s’il n’y a pas de gouttière :
.container-grid-4 {
/* container's styles */
}
.container-grid-4 > * {
/* direct children's styles */
}
Ébauche de grille en flexbox
Commençons par une grille de 4 éléments via flexbox et sans définir de gouttière :
/* moving to box-sizing (always) */
* { box-sizing: border-box; }
/* styles du conteneur */
/* hozizontal display and wrap enabled */
.container-grid-4 {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
/* direct children's styles */
/* width defined to 25% */
.container-grid-4 > * {
flex: 0 0 auto;
width: 25%;
}
Gérer la gouttière
À l’heure actuelle, gérer l’espace entre les éléments d’une grille n’est toujours pas aussi intuitif qu’il devrait l’être, nous sommes encore obligés de passer par des bidouilles pour cela.
L’une des astuce devenue un grand classique, le combo margin-left
négatif sur le parent + padding-left
sur chaque enfant, est certainement la plus prisée. Cependant, grâce au modèle particulier de Flexbox, nous allons pouvoir nous affranchir du padding
et ne conserver comme critère que le margin
.
Voici comment elle opère… Supposons que je souhaite créer trois colonnes espacées de 30px. Le principe de cette astuce est de :
-
conférer une largeur (
width
) de 33.33% à chacun des enfants moins la gouttière :width: calc(33.33% - 30px);
-
d’attribuer un
box-sizing: border-box
pour être sûr que les boîtes ne s’agrandiront pas en ajoutant du padding ou une bordure, -
appliquer un
margin-left
de 30px sur chaque enfant, -
appliquer une
margin-left
de valeur négative (-30px) sur le conteneur, ce qui aura pour effet d’étirer ses enfants et d’absorber le margin du premier enfant.
.container-grid-3 {
margin-left: -30px;
}
.container-grid-3 > * {
width: calc(33.33% - 30px);
margin-left: 30px;
}
Voir la grille avec gouttières
Automatiser avec un préprocesseur
Parvenu à ce stade, un nouveau pallier pourrait être franchi : celui d’automatiser la construction de la grille quel que soit le nombre de colonnes souhaitées et quelle qu’en soit la valeur de gouttière.
C’est à présent le boulot des préprocesseurs tels que LESS ou Sass. Pour ma part, j’ai choisi LESS pour ce tutoriel.
Créons un mixin .grid(x,y)
que l’on pourrait appliquer à n’importe quel élément HTML conteneur, et donc les paramètres x
et y
représenteraient respectivement le nombre de colonnes et la largeur de la gouttière.
La largeur des enfants en pourcentage serait calculée selon le nombre de colonnes via la formule calc(100% * 1 / @{number} - @{gutter});
:
[class*="grid-"] {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-left: -@gutter;
}
[class*="grid-"] > * {
flex: 0 0 auto;
display: block; /* IE fix */
width: ~'calc(100% * 1 / @{number} - @{gutter})';
margin-left: @gutter;
}
.grid(@number:@number, @gutter:@gutter) {
& > * {
width: ~'calc(100% * 1 / @{number} - @{gutter})';
}
}
Bonus : meilleure “sémantique” HTML
L’apport d’un mixin LESS, outre le fait d’automatiser la création de grilles, est d’épurer le code HTML et CSS en développement.
Ainsi, il ne sera plus nécessaire d’ajouter des classes supplémentaires dans notre “markup” puisque ce genre de syntaxe sera rendu possible :
ici je veux une grille de 6 colonnes
// section crée une grille de 6 colonnes espacées de 1em (défaut) chacune
.grid-perso {
.grid(6);
}
Bonus : éléments double ou triple taille
Certains éléments doivent être mis en exergue et occuper le double d’espace que leurs voisins ? Rien de plus simple avec flexbox : il suffit d'adapter la valeur de width
voire de l’automatiser avec LESS pour que cette valeur s’adapte quel que soit le nombre de colonnes.
.flexitem-double {
width: ~'calc(100% * 2 / @{number} - @{gutter})';
}
.flexitem-triple {
width: ~'calc(100% * 3 / @{number} - @{gutter})';
}
Bonus : “à la Une”
À présent, pourquoi ne pas continuer avec les bonnes choses ? Grâce à la propriété order
du positionnement flexbox, il est très simple d’intervertir l’ordre d’affichage des éléments et faire remonter un bloc avant les autres.
Il suffit pour cela de lui attribuer une valeur de order
inférieure à la valeur par défaut qu’est 0
:
// will be displayed first
.flexitem-first {
order: -1;
}
// will be displayed last
.flexitem-last {
order: 2;
}
Des Media Queries pour toutes les surfaces
Enfin, n’oublions pas le bouquet final qu’est l’adaptation à toutes les surfaces.
Là encore il est possible d’automatiser un maximum de fonctionnalités à l’aide de variables et de mixins.
Par exemple, pour forcer une grille à s’afficher en deux colonnes lorsque l’écran est réduit, voilà ce qui est envisageable :
@media (min-width: (@tiny-screen + 1)) and (max-width: @small-screen) {
& > * {
width: ~'calc(100% * 1 / 2 - @{gutter})';
}
& > .flexitem-double {
width: ~'calc(100% - @{gutter})';
}
Résultat final
Nous voici donc arrivés à la fin de notre (agréable) périple. Notre grille est prête et fonctionnelle.
Concrètement, voici le récapitulatif des codes HTML et CSS / LESS employés tout au long de ce tutoriel.
J’espère que le résultat (et sa simplicité) vous convaincront !
HTML
<div class="grid-4">
<div>1.</div>
<div>2.</div>
<div>3.</div>
<div>4.</div>
<div class="flexitem-double flexitem-first">5.</div>
<div>6.</div>
<div>7.</div>
<div>8.</div>
<div>9.</div>
<div style="margin-left: auto;">10.</div>
</div>
CSS / LESS (styles de travail)
C’est le fichier LESS qui nous servira de base de travail pour modifier les styles de notre projet.
Pour notre plus grand plaisir, il est réduit au strict minimum.
Exemple de grille de 6 colonnes espacées de 1em (défaut) chacune, appliquée sur l'élément de classe ".grid-container" :
.grid-container {
.grid(6);
}
Exemple de grille de 12 colonnes espacées de 10px chacune, appliquée sur l'élément de classe ".grid-perso-douze" :
.grid-perso-douze {
.grid(12, 10px);
}
CSS / LESS (mixins LESS)
Ces mixins sont définis une fois pour toute, il devrait être inutile d’y toucher ou de les modifier une fois qu’ils sont en place.
// grid styles for container wich has a .grid(n,g) class
// n = number of columns (default = 4)
// g = gutter value (default = 1em)
// example : .grid-container { .grid(12, 10px); }
[class*="grid-"] {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-left: -@gutter;
}
[class*="grid-"] > * {
flex: 0 0 auto;
display: block; /* IE fix */
width: ~'calc(100% * 1 / @{number} - @{gutter})';
margin-left: @gutter;
}
.grid(@number:@number, @gutter:@gutter) {
& > * {
width: ~'calc(100% * 1 / @{number} - @{gutter})';
}
& > .flexitem-double {
width: ~'calc(100% * 2 / @{number} - @{gutter})';
}
& > .flexitem-first {
order: -1;
}
@media (min-width: (@tiny-screen + 1)) and (max-width: @small-screen) {
& > * {
width: ~'calc(100% * 1 / 2 - @{gutter})';
}
& > .flexitem-double {
width: ~'calc(100% - @{gutter})';
}
}
@media (max-width: @tiny-screen) {
& > * {
width: ~'calc(100% - @{gutter})';
}
& > .flexitem-double {
width: ~'calc(100% - @{gutter})';
}
}
}
Commentaires
Merci pour ce tuto Raphaël.
Le résultat en ligne ne fonctionne pas sur mon Safari (8).... Si je rajoute une propriété "flex-wrap: wrap;", ça marche...
Mais sinon, merci pour le tuto :-D
@zemoko : ah oui tiens, Safari 8 ne reconnaît pas flex-flow. J'ai modifié le Pen, ça devrait fonctionner à présent.
c'est super, merci bq Raphael
@ghassen, @glow : de rien, j'espère que ce sera utile. Je prévois de l'intégrer dans la prochaine version majeure de KNACSS
Bonjour et merci @raphael pour ce tuto aux p'tits oignons hyper détaillé. J'aime particulièrement le fichier LESS réduit à quelques lignes ;)
Ca m'a l'air vraiment très "usefull". J'aurai besoin de ça mais je n'arrive pas à le faire fonctionner.
Que me manque-t-il pour que ça marche ?
--> http://www.lesmulots.org/formations-test.html...
@bmael :
Bonjour. Vous avez copié le code LESS tel quel dans votre fichier .css, il ne peut pas être interprêté ainsi. Il faut que le code LESS soit compilé pour générer du CSS.
Si vous êtes complètement étranger à LESS, voici comment faire vos premiers pas : http://lesscss.org/
Bonne lecture, bon apprentissage et bonne journée :)
Oui j'ai entendu parlé du LESS mais ne connais pas. Je vais donc étudier ça.
Je vous remercie.
Ce qui me fait un peu rigoler sur les outils "pour gagner du temps" comme par exemple grunt pur ne citer que lui, c'est que on "gagne" du temps pour aller le gaspiller à la cafet', au déjeuner ou en salle de jeu pour ceux qui en ont...
De toute façon, pour "voler" les contrats à la concurrence, les boites réduisent le temps de dev au max, voire à l'abus, ce qui fait que la plupart du temps, on livre toujours en retard... C'est du vécu... malheureusement, alors il faut rester de plus en plus tard le soir...
Perso je maitrise bootstrap/less, j'aime et ça me suffit, on va économiser quoi avec le reste, quelques ko? on peut largement les gagner en optimisant les images. Dans mon ancienne boite,on m'avait confié l'optimisation d'un site pour mobile. quand j'ai vu le poids des images quand j'ai repris le projet, j'ai failli avoir une attaque, surtout quand le DT insistait sur l'optimisation du code... je ne dirais qu'une chose : LOL
@quice changes de boulot si tu te suffit de bootstrap/less qui sont des technos à un instant T. Hors le web ça évolue tout le temps. C'est comme si je disais j'ai appris avec les tableaux de mises en pages et perso ça me suffit ! De plus, l'optimisation des ressources n'a rien avoir avec l'optimisation de ton système de mise en page. Donc non ça te fera même pas gagner quelque KO.
Après le temps économiser grâce à ce genre d'outil t'en fait ce que tu veux. Soit tu augmentes la buisness value de ton project soit tu vas, effectivement, boire un pot à la machine à café.
Qaund je dis j'aime et ça me suffit, il est bien entendu que c'est en attendant quelque chose de plus conséquent en terme de performance et pas une petite réécriture de ce qui éxiste déjà. pas la peine de réinventer la roue, elle éxiste déjà -____-'
Après, tu bosses comme tu veux, pour ce qui est du temps gagné, si le but est de rester plus longtemps en cafet, ben LOL. Si déjà t'arrives pas à comprendre ça, ben... ... ... ..., je ne répondrai pas à la suite... je ne vais répéter la messe pour les sourds.
@quice : "si le but est de rester plus longtemps en cafet, ben LOL".
On peut aussi voir les choses autrement.
En ce qui me concerne, j'estime que tout le temps que je dois passer sur des trucs facilement automatisables (minification, concaténation, compilation, etc.) est du temps que je ne peux pas consacrer à faire du code propre, documenté, maintenable, accessible.
Bref, c'est plutôt une question de "balance des tâches" que de simplement vouloir "travailler moins".
Bonsoir . Excusez moi de vous déranger mais j'aurais une petite question qui peux sembler bête mais après maintes recherches et essais , je ne me figure pas si ceci est possible . Voici donc ma question . Est il possible avec flexbox que mon header avec ma navbar et mon logo reste static ( comme avec position:fixed) et que mon site déroule derrière en scroll down ? Je désespère de trouver là. Merci de m'avoir lu et pour vos réponses.
Bonsoir . Excusez moi de vous déranger mais j'aurais une petite question qui peux sembler bête mais après maintes recherches et essais , je ne me figure pas si ceci est possible . Voici donc ma question . Est il possible avec flexbox que mon header avec ma navbar et mon logo reste static ( comme avec position:fixed) et que mon site déroule derrière en scroll down ? Je désespère de trouver là. Merci de m'avoir lu et pour vos réponses.
Merci beaucoup mais dommage que cela ne fonctionne pas correctement avec IE11 (les box ne remplissent pas complètement la ligne). Erreurs signalées dans Can I use et pour lesquelles Microsoft n'annonce pas de délai de correction (le problème remonté a l'air différent mais mon niveau de retraité autodidacte ne permet pas de l'affirmer !).
Je crève d'envie d'utiliser cette méthode...
D’ailleurs les flexbox d'une façon général c'est vraiment magique.
Mais pour le moment à cause de IE à la noix je m'en passe.. snif je vais pas m'amuser à gagner du temps en utilisant flexbox pour le perdre à devoir prévoir les cas LT IE11....
@cyrano25550 : ça devrait être résolu à présent avec les dernières modifs.
Bonjour Raphael,
Il semble que flex-wrap: wrap ne fonctionne pas sur android 4.1.1
En tout cas pas sur le Samsung SIII avec lequel j'effectue mes tests et ce malgré la présence de -webkit-flex-wrap: wrap;
Une idée de comment on peut régler cela ?
Merci
Bonjour Raphael,
je signale une petite coquille dans "Gérer la gouttière", 3ème li :
appliquer un margin-left de 30px sur chaque enfant (plutôt que margin-left qui ne permettrait pas de conserver un total de 50% + 50%,,
devrait être, si je ne m'abuse :
appliquer un padding-left de 30px sur chaque enfant (plutôt que margin-left qui ne permettrait pas de conserver un total de 50% + 50%),
Merci pour le tuto !
@MathieuVD : Tu dois avoir android browser je pense, il n'est malheureusement pas très à jour et me pose régulièrement des soucis. Plus généralement, sur certains navigateurs pas si vieux, le support de "flex" était partiel, et la propriété "wrap" n'était pas pris en compte.
Si tu utilises Modernizr, tu peux utiliser la classe "no-flexbox" qui tu permettras de gérer un fallback en inline-block par exemple.
Bonjour Raphael,
Tout d'abord merci pour ce tuto très intéressant !
J'ai remarqué une petite coquille dans le code css de la partie "gérer la gouttiere" :
margin-left: 30px solid transparent;
Est ce une erreur ?
Bonjour Raphaël,
merci pour le tuto... que j'ai bien du mal à reproduire.
J'ai repris le HTML+CSS (sans LESS) et je ne parviens pas à 4 colonnes avec une largeur de 25% sur les enfants.
Par ailleurs les valeurs "solid transparent" sur la margin affichent une erreur dans l'inspecteur Chrome.
Qu'est-ce qui cloche?
http://codepen.io/romainlange/pen/RPPeMg
Merci!
Ne réussissant pas à recréer la démo, j'ai trouvé une alternative en HTML & CSS: pour quatre colonnes, chaque bloc a width=24% + une margin-left=1%.
http://codepen.io/romainlange/pen/pJJGqB
Sinon, n'y a-t-il pas une erreur dans le texte?
> appliquer un margin-left de 30px sur chaque enfant (plutôt que margin-left qui ne permettrait pas de conserver un total de 50% + 50%)
> appliquer un margin-left ... plutôt que margin-left ... ?
Bon dimanche!
Bonjour Raphaël,
je reviens à la charge, mais il me semble qu'il y a un soucis dans cet article:
le code indique une largeur de 25% pour les enfants, le texte parle de 50% et l'image d'illustration montre 33,33%. Non?
Trouvé:
le teste parle de padding-left
le code de margin-left
chez moi ça marche avec border-left
http://codepen.io/romainlange/pen/RPPeMg
Merci !
Bonjour Romain (et désolé pour le délai de réponse).
Il y avait effectivement une coquille dans les explications et le code.
Il s'agit bien au final de n'utiliser que margin (pas padding ni border). Les codes sont corrigés ainsi que les exemples en ligne :
(sans LESS) : http://codepen.io/raphaelgoetter/pen/mzKrh?editors=110
(avecLESS) : http://codepen.io/raphaelgoetter/pen/BybOag?editors=110
Bonjour Raphael,
tout d'abord merci pour ce tuto !
je l'ai appliqué à mon site et je suis très content, sauf que .....
Comme Zemoko le soulignait, ça ne marche pas avec Safari ! :( .
Meme avec la petite ligne "fex-wrap: wrap;" dont il parle ! .
Les boites se mettent juste les unes en dessous des autres ! (les garces ! ).
Que faire ?
Alex
Bonjour Raphael,
petit up.
Je n'arrive tjs pas a voir pourquoi ça ne marche pas correctement avec Safari :(
Une idée? Une solution?
Bonjour Raphael,
Merci pour le tuto .
J'ai commencé à utiliser ce framework et je trouve vraiment super cool .
Alors j'ai voulu utilisé la grille pour créer une page style mosaïque (image + text)
J'ai besoin d'utiliser ' flex-item-double ' mai dans le sens vertical non horizontale
Est -il possible de faire ceci ?
s'il y a d'autre alternative veillez m'indiquer svp :)
Bonjour Raphael, j'ai testé sous :
- chrome 45
- IE 11
- Firefox 38.
L'affichage de la grille fonctionne parfaitement sous les trois navigateurs. Affichage de la grille en 3 colonnes.
Mais j'ai de gros problème pour l'impression de ces pages !
Sous firefox la grille s'imprime sous 2 colonnes
Sous Chrome, la grille s'imprime sous une seule colonne (pourquoi pas 2 colonnes comme sous firefox ??, y'a la place)
sous IE, magie : page blanche...., les pages s'affichent (27),mais sans contenu..
Bonjour,
ce tutoriel ne fonctionne pas, les exemples sont en SASS, non en LESS. Pour un débutant en LESS, ceci peut poser des soucis.
Pour ma part, je trouve que ce tutoriel est à reprendre : il est très intéressant mais non finalisé. Les exemples de codes à utiliser arrivent "après"... on ne comprend pas grand chose. C'est dommage.
une question avant que j'avance plus loin ... ce n'ai pas fonctionnel avec less ?
je suis a la recherche un petit systeme de grille responsive pour créer des vue simple (pas de menu, pas de bouton etc) juste une grille colonnable et responsive sans framework ... cela me semblait pas mal ....
@djibb :
@micker :
Bonsoir,
Je viens de retester les codes et ils semblent pourtant bien fonctionner. Voici mon test sur Codepen : https://codepen.io/raphaelgoetter/pen/mgmNdp?editors=1100