Accueil

Traduction

Tutoriel CSS - sommaire

Tutoriel CSS3 - recherche

L'auteur : Patrick Darcheville

Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site

CSS3 - révolution dans le positionnement avec les outils "grid layout" et "flexbox"

Préambule

Le positionnement des boites a toujours été, en programmation web, un point délicat. Les développeurs web ont longtemps utilisé les tableaux HTML pour mettre en forme les pages web.
Puis le CSS a proposé différentes techniques de positionnement via la propriété POSITION (voir chapitre relatif à cette propriété).
Mais beaucoup de développeurs WEB utilisaient la propriété float pour positionner les boites alors que celle-ci était initialement prévue pour disposer des éléments inline dans une boite (à gauche ou à droite du conteneur).
Nous avons vu par ailleurs qu'en transformant des éléments "block" ou "inline" en "inline-block", ceux-ci se positionnaient de front avec les marges externes précisées.

Je vous annonce une excellente nouvelle : CSS3 introduit deux nouvelles spécifications pour le positionnement des boites : flexbox & grid layout.
L'outil flexbox (boites flexibles) est déjà bien implémenté sur les navigateurs.
Concernant l'outil grid layout (positionnement en grille), est connu de la dernière version de MS Edge sortie en 2020 et bien entendu de Chrome et Firefox.

L'emploi des deux méthodes n'est pas du tout incompatible.
L'outil flexbox n'étant à l'aise que dans une dimension, est pratique pour gérer des menus, des galeries d'images, etc.
L'outil grid layout étant conçu pour les deux dimensions, sera utilisé pour la mise en forme générale de la page.
Pour prendre une exemple, l'outil "grid layout" sera utilisé pour disposer les grandes divisions de la page (les boites header, nav, article, aside, footer) tandis que l'outil "flexbox" permettra de disposer les différents DIV contenus dans la division ARTICLE et dans la division NAV.

Le positionnement en grille : outil "grid layout"

Je débute par l'outil "grid layout" (positionnement en grille).
Comme je disais plus haut, cet outil est implémenté par tous les navigateurs récents.

Une grille avec 6 cellules

Le code HTML

Aucune difficulté : 6 boites affectées de la même classe : "boite".

Le code CSS pour 2 lignes et 3 colonnes donc 6 cellules toutes identiques

La page a une largeur de 90% de celle de la fenêtre.
La page a une hauteur minimale égale à la hauteur de l'écran (min-height : 100vh). En effet "vh" signifie "viewport height" donc la hauteur minimale de la page est égale à 100% de la hauteur du viewport.

Le rendu

Aperçu de la page dans un cadre :

Le premier DIV occupe implicitement la première cellule, le deuxième DIV la deuxième cellule et ainsi de suite.
Les trois colonnes ont la même largeur, les deux lignes ont la même hauteur donc les six cellules sont identiques !
Pour les que les lignes et les colonnes aient la même hauteur / largeur il suffit de leur attribuer la valeur "auto".

Version 2 : colonne du milieu deux fois plus large que la première et dernière

Le code HTML inchangé et le code CSS devient alors ...

Notez les valeurs des propriétés grid-template-rows & grid-template-columns !
Le raccourci grid-gap : esp. lig. esp. col. remplace avantageusement les propriétés grid-row-gap & grid-column-gap.

Le rendu :

Comme les colonnes ne doivent pas avoir la même largeur, j'ai utilisé une nouvelle unité de mesure : "fr".
Pour les lignes j'ai aussi utilisé cette nouvelle unité de mesure à la place de "auto".

Organiser la structure générale de la page avec "display grid"

Donc le code HTM sera :

Quatre boites seulement !

Nous devons créer une grille de 2 colonnes et 3 lignes donc 6 cellules alors que nous n'avons que quatre divisions ...
Il n'est plus question d'une affectation implicite des boites aux cellules. L'affectation doit être explicite !

Pour l'affectation explicite des divisions aux différentes cellules de la grille nous avons trois solutions !

Première solution : fusion de cellules

Pour chaque division on précise la première cellule d'affectation et l'éventuelle fusion de cellules.

On définit d'abord une grille de trois lignes et deux colonnes donc 6 cellules.
Chaque "fr" représente ici le dixième de la hauteur /largeur disponibles.

Le rendu :

La valeur "span ..." a été ici associée à la propriété grid-column donc on fusionne (sur une même ligne) des colonnes.
Mais on peut aussi fusionner sur une même colonne des lignes ; il suffit d'associer la valeur "span ..." à la propriétégrid-row.

Deuxième solution : préciser les bornes

Pour chaque boite on précise les bornes de ligne et de colonne.
La grille comprend 2 colonnes et trois lignes. Donc les bornes de colonnes sont 1,2,3 (et non pas 0,1,2) et les bornes de lignes sont 1,2,3,4.
Ainsi la première ligne est entre les bornes de ligne 1 et 2 ; la dernière ligne est entre les bornes de ligne 3 et 4 ;
La première colonne est entre les bornes de colonne 1 et 2 ; la deuxième colonne est entre les bornes de colonnes : 2 et 3.
Extrait de la feuille de style :

Le reste de la feuille de style est inchangé.

Pour chaque sélecteur il y a deux propriétés (grid-row & grid-colunm) et pour chaque propriété il y a deux valeurs séparées par une "/". La première valeur est la borne début et la deuxième valeur est la borne fin.
Ainsi il faut lire pour HEADER : bornes de ligne de 1 à 2 (donc première ligne) et bornes de colonne de 1 à 3 (donc deux colonnes).
Personnellement, j'aime pas trop cette technique.

Le rendu est strictement identique ; donc je ne le présente pas.

Troisième solution : nommer les cellules

On nomme chaque cellule de la grille (propriété grid-template-area) ; plusieurs cellules pouvant porter le même nom. Puis on affecte à chaque division de la page un nom (propriétégrid-area)

C'est la technique que je préfère car elle me parait la plus claire au niveau du code CSS.
Je vous communique toute la feuille de style.

Apparition de la propriété grid-template-areas qui nomme les six cellules de la grille.
Les deux cellules de la première ligne se nomment "h" ; les cellules de la deuxième ligne se nomment respectivement "n" et "a" ; les deux cellules de la troisième ligne se nomment "f" ;

Apparition de la propriété grid-area qui affecte un nom de cellule à chaque grande division de la page :

Les propriétés grid-row & grid-column disparaissent !

Le rendu :

Nommer les cellules - syntaxe

L'outil "grid layout" et le responsive design

En combinant les "media queries" et le positionnement en grille on peut obtenir un site "responsive" c'est à dire qui s'adapte à tous les écrans : de l'écran géant d'un ordinateur de bureau au minuscule écran d'un "ordiphone" (comme disent les québecois).

Thème

Sur un petit écran la boite ASIDE est masquée ; chacune des quatre autres boites occupent toute la largeur de l'écran.

Le code de la partie BODY

Il est totalement indépendant de la taille de l'écran.

N'oubliez pas la balise meta viewport dans la partie HEAD!

La feuille de style

L'espacement entre rangées et colonnes est le même : 10px.
Une grille de 3 colonnes et 4 lignes.

Par défaut la largeur de BODY est égale à 800 pixels mais si largeur de la fenêtre est inférieure à 801px alors la largeur de la page = 100% et la boite ASIDE est masquée (display : none); la division "article" occupe alors toute la troisième ligne (nouvelles valeurs pour grid-template-areas).

Le rendu dans un nouvel onglet

Aperçu

Le rendu sera fonction de la largeur de l'écran. Sur votre PC réduisez progressivement la largeur de la fenêtre d'affichage.
Sur un petit écran les quatres boites (puisque ASIDE est masqué) sont les unes en dessous des autres.

L'outil flexbox : les boites flexibles

Lorsqu'on travaille avec l'outil flexbox, deux axes interviennent : l'axe principal et l'axe secondaire.
L'axe principal est défini par la propriété flex-direction et l'axe secondaire est alors l'axe qui lui est perpendiculaire.
La valeur par défaut de flex-direction est "row" (donc l'axe principal est l'axe horizontal).

Je vais vous montrer ci-dessous que l'outil flexbox est parfaitement adapté pour créer des menus responsives et produire de superbes galeries photos.

Positionnement flexible : exemple 1

Le code de la page

Le conteneur SECTION contient trois DIV.
Notez que la largeur par défaut de BODY est de 100% de la fenêtre sauf si celle-ci fait au moins 1000px (BODY fait alors 900px de large avec centrage).
Remarquez la règle de style relative à l'élément SECTION : display : flex; flex-direction : row; Ce qui signifie que SECTION est le "flex container" et les éléments contenus dans ce conteneur seront des "flex-items".
Notez que pour les trois "flex-items" je n'ai défini ni hauteur ni largeur, la taille est flexible (en fonction du contenu).

Le rendu

Les flex-items occupent toute la largeur disponible et ont tous la même hauteur.

Exemple 2 : l'axe principal est l'axe vertical

Le code

Le code de la page est strictement identique au précédent sauf dans la règle de style relative à SECTION : display : flex; flex-direction : column;
Donc cette fois l'axe principal est l'axe vertical (et l'axe secondaire sera l'axe horizontal).

Le rendu

Fixer une largeur à chaque flex-item

Cette fois je fixe pour chaque "flex-item" une largeur : div {width : 250px ; margin : 10px ; }
Axe principal = axe horizontal.

Le rendu

Problème : sur un grand écran les trois items sont alignés à gauche sur l'axe horizontal et sur un petit écran la largeur de 250px n'est pas respectée.

La solution

Il faut rendre possible un saut de ligne lorsque le "flex-container" est étroit.
Il faut donc modifier la règle de style relative au conteneur.
section {display : flex; flex-direction : row; flex-wrap : wrap; }
J'introduis une nouvelle propriété flex-wrap avec la valeur "wrap". Ce qui veut dire que les items peuvent passer sur une nouvelle ligne si c'est nécessaire.
Bien sûr, si l'axe principal est l'axe vertical il s'agira d'un saut de colonne.
Valeur par défaut de cette propriété est "nowrap" (saut de ligne impossible).

Le rendu :

Sur un petit écran le troisième item passe à la ligne puis le deuxième si la fenêtre est encore plus étroite. Observez que les items sont alignés à gauche (en début de l'axe de façon générale).

Gérer l'alignement des blocs sur l'axe principal

Pour l'esthétique il faut une distribution équilibrée des blocs sur l'axe principal. C'est l'affaire de la propriété justify-content.

Exemple de belle distribution des blocs

Le "flex-container" contient six "flex-items" ; la répartition des blocs selon l'axe horizontal doit être équilibrée ; un saut de ligne doit être possible.

Le code :

La page fait 1300px de large ou 100%.
Il y a en fait six DIV contenu dans le conteneur SECTION.
Notez bien la nouveauté dans la règle de style de SECTION : ...justify-content : space-around;

Aperçu de la page dans un iframe :

Selon la largeur de la fenêtre d'affichage, les six boites sont de front ou sur deux lignes voire sur 3 lignes avec à chaque des marges entre les items et les extrémités.

Centrer H & V un bloc unique dans son conteneur

Piqure de rappel : en CSS 2 le centrage H& V d'une boite dans son conteneur était un vrai casse-tête (voir chapitre sur la propriété POSITION).
Avec l'outil flexbox le centrage H & V d'une boite dans son conteneur devient un jeu d'enfant. Il suffit de demander un centrage du "flex-item" sur les deux axes.

Le code de la partie BODY

La feuille de style

J'utilise donc les propriétés justify-content & align-items

Le rendu

Galerie photos avec display flex

La technique de positionnement "display inline-block" peut être remplacée par l'outil "flexbox" pour les blocs de texte mais aussi pour les images à condition de prendre certaines précautions comme je le montre pour le thème "galerie photos" ci-dessous.

Galerie photos - solution erronée

Certaines images sont déformées car elles ont toutes les mêmes dimensions alors qu'elles n'ont pas à l'origine le même ratio largeur/hauteur.

Galerie photos - bonne solution

Solution avec objet-fit : cover :

Certaines images sont un peu rognées.

Solution avec objet-fit : contain :

Certaines images n'occupent pas toute la zone d'affichage.

Le code correspondant

Par rapport à la version erronée je me suis contenté de rajouter pour le sélecteur img la règle object-fit: cover/contain.
Ce qui veut dire que les images ne doivent jamais être déformées.

La propriété object-fit

La nouvelle propriété CSS object-fit peut s'appliquer aux éléments img, video, object, embed.
Cette propriété vise à ajuster la taille de l'élément dans sa zone de contenu.

Remarque : la propriété background-size peut prendre aussi les valeurs "cover" et "contain" et avec les mêmes conséquences : non déformation de l'image dans les deux cas mais éventuellement rognage ou zone blanche.

Dans mon site (celui que vous visitez) les menus principaux sont bâtis avec l'outil flexbox

Le CSS (extrait de la feuille de style externe)

Donc un code CSS très léger et responsive (quelque soit la largeur du terminal, il y a un bon rendu.

Le code HTML (extrait) dans la page d'accueil

Le code HTML ne présente aucune difficulté.

Le code HTML en fin de chaque page

À la fin de chaque page il y a une boite nav avec trois liens sous forme de boutons.