Accueil

Traduction

Tutoriel CSS - sommaire

Tutoriel CSS - 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 positionner textes et images.
Puis le CSS a proposé différentes techniques de positionnement via la propriété POSITION pouvant prendre les valeurs : fixe, absolu, relatif.
Mais beaucoup de développeurs WEB utilisaient la propriété float pour positionner les boites alors que cette propriété était initialement prévue pour disposer des éléments inline (des images par exemple) dans une boite.

Nous avons vu par ailleurs qu'en transformant des éléments de type DIV ou IMG en "inline-block", ceux-ci se positionnaient de front (et non plus les uns en dessous des autres).

Excellent 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), il est connu de la dernière version de MS Edge sortie en 2020.

Ces deux nouveaux outils se complètent parfaitement.
L'outil "grid layout" permet de construire la structure générale de la page alors que l'outil "flexbox" n'est vraiment à l'aise que dans une seule direction ...
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, par exemple.

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

Dans le cadre d'un responsive basique 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.

Observez le rendu

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.
Observez 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 est simple :

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).
Le rendu

Personnellement, j'aime pas trop cette technique.

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 division :

Les propriétés grid-row, grid-column disparaissent et sont remplacées par grid-area
Essayez !

Comme vous avez pu l'observer ces trois solutions donnent exactement le même rendu, et c'est heureux.
Donc à vous ce choisir la méthode qui vous convient et vous oubliez les deux autres ...
Notez bien que les propriétés qui commencent par "grid-template" sont utilisées au niveau du "grid-container" (BODY dans mes exemples). La propriété grid-area est utilisée au niveau de chaque grande division.

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).

Structure générale de chaque page d'un site

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 lignes 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% de la fenêtre. et la boite ASIDE est masquée (display : none); la division "article" occupe alors toute la troisième ligne.
Observez le rendu sur un PC puis réduisez la fenêtre pour simuler l'affichage sur un petit écran

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.

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).
Notez 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 que les enfants de SECTION seront des "flex-items".
Notez que pour les trois "flex-items" je n'ai défini ni hauteur ni largeur !

Observez le rendu !
Sur PC, réduisez la fenêtre pour simuler l'affichage sur un petit écran.

Les trois "flex-items" sont toujours sur la même ligne. Les différents items n'ont pas la même largeur ; Largeur en fonction du contenu. Les trois items occupent toute la largeur disponible.

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

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 !

Observez le rendu !
Les trois "flex-items" sont toujours sur la même colonne. La hauteur de chaque item est fonction du son contenu et des dimensions du conteneur. Chaque item occupe toute la largeur disponible.

Exemple 3

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

Sur un grand écran les trois items sont alignés à gauche sur l'axe horizontal mais 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" qui veut dire "saut de ligne impossible".

Le rendu ; réduisez la fenêtre pour simuler l'affichage sur un petit écran

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 items selon les deux axes

La propriété justify-content gère l'alignement selon l'axe principal et la propriété align-items gère l'alignement selon l'axe secondaire.

justify-content

align-items

Exemple

Le "flex-container" contient six "flex-items".
La répartition des items dans le conteneur doit être équilibrée.
Le code (extrait) :

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;

Testez ce code ; réduisez progressivement la fenêtre.

Selon la largeur de SECTION 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.

Positionner une boite flexible en haut à gauche du flex-container

Nous voulons qu'un item unique soit positionné en haut et à gauche dans son conteneur.
Cette fois nous devons raisonner sur les deux axes.

Le code de la partie BODY

Code CSS

La propriété justify-content gère l'alignement sur l'axe principal (ici l'axe vertical)
La propriété align-items gère l'alignement sur l'axe secondaire (ici l'axe horizontal).

Le rendu !

Le "flex-item" est bien positionnée en haut et à gauche de son flex-container ("parent").

Le centrage d'une boite flexible dans son conteneur

En CSS 2 le centrage horizontal ET vertical d'une boite dans son conteneur était un vrai casse-tête.

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

Observez 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

Le rendu

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.
Je n'ai pas utilisé la propriété object-fit pour le sélecteur img donc c'est comme si j'avais réglè cette propriété à "fill" (sa valeur par défaut).
Voir la syntaxe de la propriété ci-dessous.

Galerie photos - bonne solution

Le rendu

Observez le code !

Par rapport à la version erronée je me suis contenté de rajouter pour le sélecteur img la règle : object-fit: cover.
Ce qui veut dire qu'éventuellement les images seront rognées pour qu'elles aient toutes les mêmes dimensions et sans être déformées.

Créez une page avec le même code que celui indiqué ci-dessus sauf object-fit : contain.
Vous verrez alors que les images ne sont pas rognées mais n'ont pas toutes la même hauteur pour respecter les proportions.

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.

La propriété background-size (qui est associée à background-image pour gérer l'image de fond d'une boite) 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 rognage éventuel avec "cover" et non remplissage de toute la hauteur du conteneur avec "contain".

Quid des anciennes techniques de positionnement

Il est évident qu'avec toutes les améliorations apportés par les modèles de grille et boites flexibles, les anciens outils auront un usage de plus en plus marginal.

La propriété float

Pour positionner une image miniature ou une lettrine en haut à gauche ou à droite d'une boite avec le texte tout autour, continuez d'utiliser float.
C'est le retour aux sources pour cette propriété.

Position absolute

Pour supersposer des blocs vous serez toujours obligé d'utiliser la propriété "position" avec la valeur "absolute" et conjointement avec "z-index" pour gérer l'ordre d'empilement voir le modifier ...

Position fixe

Un menu ancré par rapport à la fenêtre c'est pratique; alors position : fixed & z-index sont encore incontournables !

Position relative

Je ne vois plus qu'un seul intérêt à position : relative. Si cette valeur est affecté à un conteneur, les positions en absolu des "enfants" sont alors déterminées par rapport au coin haut gauche du conteneur (et non pas par rapport au coin haut gauche de l'écran).

Display inline-block

Comme je l'ai déjà montré, cette technique de positionnement peut être remplacée avantageusement par "display flex".
Si les "flex-items" sont des images, pensez à utiliser la nouvelle propriété object-fit !