Le web des années 2010
Ils faisaient bien de la mise en page plus complexe sur les sites web dans les années 2000 mais on n'as pas vu ces techniques au dernier chapitre parcequ'on ne les utilise plus puisqu'elles ont été chamboulées par une technique en 2009.
Enfin, quand je dit "qu'on utilise plus" ... c'est encore comme ça que ça se passe dans les emails et dans d'autres recoins un peu obscurs du web. Mais bon... (et oui, un email est un document HTML)
Flexbox
Cette fameuse technique de 2009 est Flexbox.
On a vu que les éléments peuvent être bloc ou inline et on peut le contrôler via la propriété CSS display. Pour forcer mes images à êtres des bloc, je pourrais écrire:
img {
display: bloc;
}
Mais maintenant on a une nouvelle option. flex. Un élément ayant flex est comme un bloc, sauf qu'il ne vas plus disposer ses éléments en utilisant la logique du "flux document" comme on l'as vu jusqu'ici.
À la place, un élément flex va disposer tous ses enfants les uns à côté des autres de gauche à droite.

Et voilà, bienvenue à boites-land, maintenant on va se mettre à emballer des groupes d'éléments dans d'autre éléments qu'on ne verra pas mais qui auront la charge de les mettre en page. En général, on appelle ces éléments englobants "conteneurs".
Remarquez que dans la flexbox, plus personne ne prend 100% de la largeur du parent. Par défaut, tous les éléments contenus prennent la place dont ils ont besoin et pas plus.
Les éléments wrappers, <article>, <section>, <div>, et les autres
De manière générale on a 3 éléments HTML dont on se sert pour faire office de conteneur.
<article>: pour ce qui est "autonome" dans le sens où on pourrait facilement le transplanter lui et son contenu sur un autre site.<section>: pour un morceau d'un tout. Donc un<body>peut avoir des sections tout comme un<article>peut avoir des sections.<div>: pour le reste
Et on en a quelques-uns qui sont plus spécifiques comme main, header,nav aside, et footer.
Techniquement, on pourrait tout faire avec des div (et c'est d'ailleurs ce que font pas mal de grosses entreprises, allez-y appuyez sur F12 dans outlook mdr) mais plus vous utiliser les bons éléments, plus vous respectez les conventions, et plus vous bossez proprement, alors plus les bots, les technologies assistives et vous même serez en mesure de bien lire et manipuler le code.

Challenge
Donc maintenant si on fait usage des flexboxs, on peut arrêter de tout disposer verticalement et faires des trucs comme ceci
Reprenez votre projet nyan 5 et faites cette page.
Solution : nyan5v2/index.html
Les propriétés flex
Propriétés pour le parent
Ces propriétés sont à mettre sur l'élément qui est display flex, ce qui peut paraître évident, mais c'est en contraste avec des propriétés qui sont pour les enfants d'un conteneur flex.
Ces propriétés ne fonctionnent uniquement sur des éléments ayant la propriété display:flex.
gap: une distance à mettre entre chaque enfant du conteneurs.
.container{
display: flex;
gap: 1rem;
}
.child{
padding: 1rem;
color: white;
background-color: #ff1460;
}
<div class="flex">
<div class="child">child_1</div>
<div class="child">child_2</div>
<div class="child">child_3</div>
</div>
flex-direction : Par défaut, une flexbox va disposer ses enfants de gauche à droite. Cette propriété permet de changer ca en spécifiant l'une des valeurs suivantes
row: la valeur par défaut, de gauche à droite ➡️column: du haut vers le bas ⬇️row-reverse: de la droite vers la gauche ⬅️column-reverse: du bas vers le haut ⬆️
justify-content : Permet de modifier le placement des enfants le long de l'axe principal, donc l'axe horizontal dans un row ou row-reverse, et vertical dans un column ou column-reverse.
start: la valeur par défaut, place les éléments à partir du débutend: place les éléments à partir de la fincenter: place les éléments au centre, laissant un espace entre le début et le premier élément ainsi que la fin et le dernier élémentspace-between: reparti les éléments équitablement le long de l'axe, de sorte à ce qu'il y ai le même espacement entre les élémentsspace-evenly: commespace-betweensauf que l'espacement sera aussi réparti entres les bords du conteneur et le premier et dernier élément.
align-items : Permet de modifier l'alignement des enfants sur l'axe transversal, donc vertical pour un row ou row-reverse, et horizontal pour un column ou column-reverse.
stretch: la valeur par défaut, étire les éléments pour qu'ils prennent la totalité de la place disponiblestart: place les éléments au début de l'axeend: place les éléments à la fin de l'axecenter: place les éléments au milieu de l'axe
Ci-dessous un petit module interactif pour essayer les valeurs
Propriétés pour les enfants
flex-grow : Définit le nombre de parts que l'élément prendra de l'espace qui reste une fois que tous les éléments sont disposés. Par défaut cette valeur est à 0.
Tous les éléments prennent ce dont ils ont besoin par défaut. Puis l'espace restant est partagé entre les enfants qui ont une propriété flex-grow. Si il n'existe qu'un seul enfant avec flex-grow alors peu importe la valeur, il prendra toute la place restante.
align-self : permet de changer son propre alignement sur l'axe transversal du conteneur.
- stretch : la valeur par défaut, étire l'élément pour qu'il prennent la totalité de la place disponible
- start: place l'élément au début de l'axe
- end : place l'élément à la fin de l'axe
- center: place l'élément au milieu de l'axe
![]()
![]()
Eh mais attend, ça ressemble vachement aux auto-layouts de figma
![]()
![]()
![]()
![]()
![]()
C'est même pas que ça y ressemble, c'est littéralement la même chose. Par défaut dans figma tout tes trucs ont des coordonées en x:y, sauf qu'on sait que ça marche pas comme ça dans le web. En revanche si tu fait une imbrication d'auto-layouts et de grids (tu va voir bientôt) alors on a une hiérarchie utilisable dans la maquette.
![]()
![]()
Mais ça marche pourtant super bien quand je fais sans auto-layout.
![]()
![]()
![]()
![]()
![]()
Ouais mais tous les alignements que t'as fait à l'arrache, eh ben il faudra les deviner au moment de faire la page pour de vrai. Bon courage pour transformer la maquette sans avoir de trucs qui pètent.
Challenge
Faites vous un linktree.
exemple de ce que je vous demande
Réponse: linktree/index.html
vw et vh
vw et vh sont des dimensions, 1vw étant "1% de la largeur du viewport" et 1vh etant "1% de la hauteur du viewport".
Je dit "viewport" plutôt que "fenêtre" ou "navigateur" parce que ce n'est pas la même chose.

et comme ça on peut revenir sur nyan5v2 et garantir que le footer est en bas de la page en faisant ceci:
/* [...] */
body{
/*tu me fais au moins la hauteur du viewport, plus si tu veux*/
min-height: 100vh;
display:flex;
flex-direction:column;
/*[...]*/
}
main{
/*je suis le seul élément du body à avoir un flex-grow*/
/*donc le header prend ce qu'il lui faut, et je prend tout ce qu'il reste*/
/*poussant le footer tout en bas de la page qui lui aussi ne prend que son necessaire*/
flex-grow:1;
/* [...] */
}
/*[...]*/
Je n'ai pas voulu vous le montrer avant parce que beaucoup de gens que j'ai vu commencer par là on envie de tout faire avec ça (et/ou position:absolute), finissant par perdre le contrôle de leur layout.
Grid
La totalité ou presque des layouts conventionnels sont faisables uniquement avec flexbox. En bonne partie parce qu'ils sont devenus conventionnels pendant l'époque flexbox. Mais très souvent on s'est retrouvé à imbriquer pleins de flexbox pour créer un conteneur en deux dimensions. Pour faire ce genre de conteneur directement on a eu display:grid.
Propriétés pour le parent
On peut utiliser display:flex directement, mais il faut faire quelques trucs en plus pour un display:grid parce que sinon on se retrouve vaguement avec un équivalent à une colonne flex.
Il faut définir notre grille, il n'est pas possible pour le navigateur de deviner vos besoins, une 2x8? une 4x4? une 8x2?
grid-template-columns et grid-template-rows sont les propriétés qui permettent de définir le nombre de colonnes et de lignes mais aussi leur dimensions.
display: grid;
grid-template-columns: 100px 50px;
grid-template-row: 100px 50px;
Et voilà, nous avons maintenant une grille dans laquelle nous pouvons mettre 4 éléments.
- le 1er aura 100x100 pixels d'espace
- le 2ème aura 50x100
- les 3ème aura 100x50
- le 4ème aura 50x50
Il est évidemment possible d'utiliser toutes les autres unités de longueur.
Ceci dit, je vous déconseille % parce que les grid ont une unité spéciale, le fr. Un fr représente une part, une FRaction, de l'espace restant après avoir distribué les tailles fixes, comme flex-grow.
display: grid;
grid-template-columns: 3fr 1fr;
grid-template-row: 3fr 1fr;
Cette grille permet également de rentrer 4 éléments
- le 1er aura 3 quarts de la largeur de la grille et 3 quarts de la hauteur
- le 2ème aura 1 quart de la largeur et 3 quarts de la hauteur
- les 3ème aura 3 quarts de la largeur de la grille 1 quart de la hauteur de la grille
- le 4ème aura 1 quarts de la largeur de la grille 1 quart de la hauteur de la grille
Si vous voulez beaucoup de lignes ou de colonnes similaires, il existe le mot clef repeat() qui prend entre ses parenthèses d'abord la quantité puis une taille.
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-row: repeat(12, 1fr);
Et comme ça, on a une grille de 12x12, chaque case faisant 1/12 de la largeur de la grille par 1/12 de la hauteur de la grille.
Tailles implicites
![]()
![]()
Ok, mais qu'est ce qu'il se passe si j'y met plus que 12x12 = 144 éléments?
On arrive dans ce que l'on appelle les lignes et les colonnes "implicites" de la grille.
Par défaut, les éléments en trop iront dans des nouvelles lignes. Et par défaut la hauteur de ces nouvelles lignes est auto donc "aussi haut que nécessaire pour faire rentrer les éléments mais pas plus", donc chacune de ces lignes sera aussi haute que le plus haut de ces éléments, nous donnant potentiellement des lignes implicites avec des hauteurs différentes en fonction de leur contenu.
Pour prendre le contrôle de notre grille implicite, ça se fait via grid-auto-columns et grid-auto-rows.
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-row: repeat(12, 1fr);
grid-auto-rows: 100px;
Avec ça, chaque rangée implicite fera 100 pixels de haut.
![]()
![]()
Mais pourquoi les colonnes implicites existent si le debordement est géré par des nouvelles lignes?
En effet les éléments sont placés de gauche à droite en commençant par la première ligne et retournent à la ligne d'après quand on tombe à cours de colonnes.
Mais il est possible de changer ce comportement avec grid-auto-flow:column, dans ce cas la grille sera remplie de haut en bas passant à la colonne d'après quand on tombe à court de lignes. Débordant donc dans des colonnes implicites.
Tout ça est utile si vous voulez une grille avec un certain nombre de colonnes mais un nombre infini de rangées (ou l'inverse). Si je reprend l'exemple juste au-dessus mais que je ne donne aucune rangçée explicite, alors j'ai une grille de 12 colonnes avec une infinitée de lignes de 100px.
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-rows: 100px;
Alignements
align-items : Aligne verticalement les éléments relatif à leurs cases (ou relatif à leur rangée, c'est pareil)
- mêmes mot clefs que le
align-itemsde flexbox
justify-items : Aligne horizontalement les éléments relatif à leurs cases (ou relatif à leur colonne, c'est pareil)
stretchstartendcenter
align-content : Aligne les rangée verticalement relatif au corps de la grille
start(par défaut)endcenterspace-betweenspace-evenly
justify-content : Aigne les colonnes horizontalement relatif au corps de la grille
start(par défaut)endcenterspace-betweenspace-evenly
Note : dans le cas d'un grid-auto-flow:column ils changent tous comme avec flex-direction:column
Areas
Il est possible de donner des noms à certaines cases et groupes de cases.
grid-template-areas: ". . ." ". a_51 a_51" ". a_51 a_51";
Si j'applique le css à un élément vide, je peux quand même visualiser la grille grâce à l'outil spécialisé dans les devtools
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(3, 100px);
grid-template-areas: ". . ." ". a_51 a_51" ". a_51 a_51";
Vous remarquerez que les cases pour lesquelles on avait . n'ont pas le nom . parce que c'est une valeur spéciale qui indique l'absence de nom.
Pourquoi faire des zones avec des noms? Eh bien…
Propriétés pour les enfants
Placement
... pour pouvoir précisément placer certains enfants!
.manualy_placed {
grid-area: "a_51"
}
Vous remarquerez que l'élément prend toute cette zone qui fait 2 colonnes et 2 rangées.
Mais ce n'est pas la seule manière de placer un élément, grid-area peut aussi prendre des coordonnées.
grid-area: 1 / 2 / 3 / 2;
Là on dit qu'on part de la 1ère rangée et 2ème colonne, pour aller à la 3ème rangée et 2ème colonne.
Personnellement je n'en suis pas très fan.
On a aussi le mot clé span qui peut remplacer la 3ième et/ou la 4ème coordonee. Span va spécifier de combien on s'étend.
grid-area: 1 / 2 / span 1 / span 2;
Dans cet exemple on spécifie que l'on commence à la 1ère rangée, 2ème colonne et qu'on fait 1 rangée de haut et 2 de large.
Et dernièrement, on peut aussi spécifier des positions à partir de la fin de la grille en utilisant des nombres négatifs. -1 étant la dernière, -2 l'avant dernière, -3 l'antépenultième (ouais c'était l'occase de le caler, j'avais envie) etc....
grid-area: 1 / 1 / -1 / -1;
Étant donc une zone qui prend toute la grille, peu importe le nombre de rangées et de colonnes.
Alignement
align-self: permet de redéfinir la valeur d'align-items pour l'enfant en question
justify-self : permet de redéfinir la valeur d'justify-items pour l'enfant en question
fit-content
Il est possible d'être un bloc, flex, ou grid et de NE PAS faire la largeur du contenant en via la largeur spéciale fit-content. Gardant ainsi le comportement bloc de retour à la ligne avant et après.
width: fit-content;
Challenge: "Composition 2"
Reproduisez au mieux la grille ci-dessous.
Pas la peine que ce soit une reproduction parfaite, vous pouvez visiter cette demo (sans appuyer sur F12 (ᵔᗜᵔ)) pour voir.
indice : les gap sont noir, donc la couleur de fond de la grille est noir, pas blanc.

Solution : mondrian.html
grid, la shorthand pour les gouverner tous
Cette propriété permet de spécifier, les rangées et colonnes explicites et le nom des areas. les rangées et les colonnes implicites, et le flow.
Est-ce que ça ne va pas être illisible si ça fait tout ça?
Ça dépend comment on s'y prend.
La manière dont je le fais n'utilise pas la partie implicite et ne change pas le flow.
Et si je voulais l'utiliser pour faire la grille typique d'une appli je pourrais l'écrire comme ça sans rien faire de particulier.
grid: "header header" auto "nav nav" auto "aside main" 1fr "footer footer" auto / auto 1fr;
Mais en insérant quelques retours à la ligne, et quelques tabulations pour aligner verticalement, et tout se retrouve parfaitement en place.
grid:
"header header" auto
"nav nav" auto
"aside main" 1fr
"footer footer" auto
/auto 1fr;
bon, le désavantage c'est qu'il faut spécifier des grid-area pour tous les enfants, du coup ça explose notre CSS et ça demande pas mal de manutention si on veux bouger des trucs.
header{
grid-area: header;
}
nav{
grid-area: nav;
}
aside{
grid-area: aside;
}
main{
grid-area: main;
}
footer{
grid-area: footer;
}
Mais bon ¯\ʕ•ɷ• ʔ/¯ c'est super pratique pour faire le layout général de la page.
Challenge
Reproduisez la page ci-dessous, idéallement en y mettant votre contenu.
Pour vous faciliter la tâche, regardez la documentation de :
- background-image : https://developer.mozilla.org/en-US/docs/Web/CSS/background-image
- background-size : https://developer.mozilla.org/en-US/docs/Web/CSS/background-size
afin de pouvoir appliquer des images aux fonds de conteneurs existants, plutôt que d'avoir des <img>. Par contre, c'est une technique pour habiller le fond d'éléments, en l'état vos images ne feront plus partie du conetenu du document et pourraient donc ne pas être prises en compte par les techno assistives.
Solution gridfolio.zip
Media queries
Les media queries permettent une mise en forme conditionnelle.
Et c'est important, parce que dans les annees 2010 on a vu l'arrivee du smartphone, mais on a aussi fait un passage des ecran 4:3 vers des ecrans 16:9 pour les ordinateurs.
Elles démarre par @media et sont valable pendant tout un bloc, comme ceci
@media print {
body {
color: black;
background-color: white;
}
}
La media query étant un bloc dans lequel on peut mettre du CSS, et dans cet exemple plus précisement on dit que le fond du <body> sera blanc et son texte noir quand la page sera affichée pour impression (Ctrl + P). Ce qui pourrait être utile à inclure dans le CSS d'un dark mode pour que le site soit quand même imprimé noir sur blanc. Ou pour passer d'une police sans-serif à une police avec.
![]()
![]()
Mais qui imprime des sites sur papier?
![]()
![]()
![]()
![]()
![]()
Le format "epub" pour les e-book, qu'on utilise principalement sur des tablettes e-ink, peut être imprimé. Et devine quoi, un epub c'est jamais qu'un zip qui contient des pages HTML/CSS (avec des limitations)
Donc en pratique, on peut écrire des sites web, qui sont aussi des livres.
screen
Comme print, mais pour les écrans
min-width et max-width
Ok, ça c'est le gros poisson. Ces media queries permettent d'appliquer du style si la largeur de l'écran est plus petite ou plus grande qu'une certaine largeur.
@media (min-width: 1000px) {
body {
background-color: red;
}
}
ici, min-width s'applique si la page est plus large que 1000px, autrement dit si elle fait "au moins" 1000px de large.
max-width c'est exactement l'inverse.
width
C'est une version alternative et plus récente de min-width et max-width
@media (width > 1000px) {
body {
background-color: red;
}
}
Ce bloc revient au même, le fond sera rouge quand la page sera plus large que 1000px. Personnellement je trouve ça beaucoup plus clair.
Pourquoi vous avoir montré min-width et max-width?
Parce que c'est une solution plus ancienne, donc plus documentée et répendue. En l'état, les vieilles solutions on ne s'en debarassera pas
Pour l'anecdote, je viens de demander à l'un des tout derniers "thinking models" au moment de l'écriture(21/05/2025) (et de la réecriture 29/10/2025) et j'ai eu une recommandation d'utiliser max-width ou sinon de le faire en javascript (lol).
Exercice
Reprennez le projet gridfolio pour qu'il s'adapte mieux à la largeur de la fenêtre en fournissant une mise en page différente sur ordinateur, tablette, et téléphone.
Comme ceci : GridfolioV2