Valentin Dupas

💡 If this is the first course you read from me, please read this small thing : about my courses

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" ... ça marche encore et c'est comme ça que ça se passe dans les emails et dans d'autres recoins un peu obscurs du web. Mais bon...

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. Je pourrais 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 ces éléments en utilisant le "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.

Pasted image 20250330003846.png

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. 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 ou on pourrait facilement le transplanter sur un autre site.

<section> : pour un morceau hermétique 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, 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 le code.

à gauche des tags semantiques et à droite tous les elements sont des div

Challenge

Donc maintenant si l'on transforme l'un d'entre eux en flexbox on peut arrêter de tout disposer verticalement et faires des trucs comme ceci

nyan5v2

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 a 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 que sur des éléments ayant la propriété display:flex. (avec certaines exceptions comme align-items qui peut maintenant se mettre sur des éléments bloc, même si il a fallu attendre ~12 ans après la sortie de flexbox pour ça)

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>
child_1
child_2
child_3



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ébut
  • end : place les éléments à partir de la fin
  • center: 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ément
  • space-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éments
  • space-evenly : comme space-between sauf 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 disponible
  • start: place les éléments au début de l'axe
  • end : place les éléments à la fin de l'axe
  • center: place les éléments au milieu de l'axe

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



Challenge

Faites vous un linktree.

exemple d'un vrai

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.

viewport is the inside

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 que je veux*/
    /*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.

Demo live tableau: "ApeuprèTube"

  • decomposition -> restructuration

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é à composé 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 avec l'équivalent d'une colonne flex mais pas tout à fait.

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 4 é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?"

Vous aurez remarqué que 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.

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

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-items de flexbox

justify-items : Aligne horizontalement les éléments relatif à leurs cases (ou relatif à leur colonne, c'est pareil)

  • stretch
  • start
  • end
  • center

align-content : Aligne les rangée verticalement relatif au corps de la grille

  • start (par défaut)
  • end
  • center
  • space-between
  • space-evenly

justify-content : Aigne les colonnes horizontalement relatif au corps de la grille

  • start (par défaut)
  • end
  • center
  • space-between
  • space-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 j'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 démarre l'on commence à la 1ere 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 la solution (sans appuyer sur F12 (ᵔᗜᵔ)) pour voir : demo

indice : les gap sont noir, donc la couleur de fond de la grille est noir, pas blanc.

Pasted image 20250401121356.png

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

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.