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