CSS 3 - Le positionnement :

Introduction :

Nous avons vu au chapitre précédent le modèle de boîtes et plus particulièrement comment modifier la hauteur, la largeur, l'espacement de ces boîtes. Nous allons maintenant voir comment vont se positionner ces boîtes dans une page HTML et également comment intervenir sur ce positionnement.

Important

Même si tous les positionnements sont vus ici, concentrez-vous sur le positionnement flex qui est le plus récent et utile pour positionner les différentes zones de votre site.

En ligne et en bloc :

À l'origine en HTML4, on distinguait deux types de balises de structure : le type en ligne ou le type bloc.

Les éléments de rendu "bloc" servent à distinguer les parties entières de texte, comme des titres, des paragraphes, des listes, des citations, etc. Voici une liste des éléments de type bloc : div, p, h1 ... h6, ul, ol, table, pre, form, blockquote, etc.

Les éléments de type bloc se placent toujours l'un en dessous de l'autre par défaut. Par exemple : une suite de paragraphes (balise <p>) ou les éléments d'une liste (balise <li>). Par ailleurs, un élément de type bloc occupe automatiquement, par défaut, toute la largeur disponible dans son conteneur.

Les éléments de type en ligne se placent toujours l'un à côté de l'autre afin de rester dans le texte. Par exemple : la mise en évidence d'une partie de texte à l'aide de la balise <em>.

Prenons l'exemple d'une image qu'on insère dans un document (.doc) de Word (Microsoft), on peut choisir dans les propriétés de l'objet si on désire que l'image apparaisse dans le texte ou comme étant un élément séparé :

Une image insérée en ligne : Une image insérée comme un bloc :
Mon image apparaît dans le texte. exemple d'image en ligne Vous êtes bienvenus dans ce cours ! Mon image apparaît comme un bloc séparé.
exemple d'image en ligne
Vous êtes bienvenus dans ce cours !

Chaque navigateur possède une feuille de style par défaut dans lequel il définit l'affichage en bloc ou en ligne des éléments HTML. Voici donc une raison pour laquelle le rendu HTML pour différer d'un navigateur à un autre. Maintenant pour les éléments les plus courants, vous ne verrez pas de différence (ouf !), les paragraphes sont toujours affichés en bloc par défaut quel que soit le navigateur utilisé.

Important

Il faut savoir qu'en HTML5 le typage des éléments HTML en bloc ou en ligne n'est plus d'actualité. Le navigateur possède une feuille de style par défaut dans laquelle chaque élément HTML est défini en ligne ou en bloc ou encore en table via la propriété display (voir ci-dessous). Le développeur web, quant à lui, peut utiliser cette propriété pour modifier le comportement par défaut donné par le navigateur. Un élément HTML ayant donc un rendu par défaut en ligne peut très bien devenir un bloc et vice-versa.

Le positionnement des boîtes :

Pour afficher une page web, le navigateur interprète le flux des éléments de type bloc de manière séquentielle, c'est-à-dire du début à la fin du fichier HTML en les affichant au fur et à mesure, les blocs étant placés les uns en-dessous des autres, séparés par une ligne (fictive). Les éléments en ligne quant à eux sont placés à la queue-leu-leu sur la même ligne, selon leur ordre d'apparition.

Il est néanmoins possible de modifier cet affichage par défaut (statique) en spécifiant un positionnement différent : absolu (absolute), relatif (relative) ou fixe (fixed). Dans chacun de ces modes, le positionnement de la boîte peut être spécifié pour l'un ou l'autres des côtés : top (côté supérieur de la boîte par rapport au côté supérieur de l'élément de référence), bottom (côté inférieur), right (côté droit) et left (côté gauche), l'élément de référence dépendant du type de positionnement. Il est déconseillé d'utiliser des valeurs négatives car certains navigateurs les interprêtes de manière personnelle.

La manipulation de ces positionnements peut être délicate car elle risque de produire des recouvrements de blocs.

Une autre manière de positionner des éléments d'une page HTML est d'utiliser le mode flottant (float) qui permet de construire des menus, de créer une colonne, etc.

Positionnement absolu (position: absolute) :

Le positionnement absolu est calculé à partir des côtés du document. Par exemple, la combinaison des propriétés CSS.

position: absolute; et left; 10%; va déplacer le bloc concerné par ce style par ce style de 10% par rapport au côté gauche du document.

Positionnement relatif (position: relative) :

De manière similaire, le positionnement relatif est calculé à partir de l'élément bloc précédent.

Positionnement fixe (position: fixed) :

Le positionnement fixe est calculé à partir du coin supérieur gauche de la fenêtre du navigateur.

La valeur sticky est la même chose que la valeur fixed, c'est-à-dire l'élément ne bouge pas, mais il est déclaré comme un élément adhérent et plus fixe.

La différence entre un élément fixe et un élément adhérent est leur comportement lorsqu'on fait défiler la page, c'est-à-dire leur interaction avec le flux de la page et leur positionnement relatif à l'écran. En gros, un élément fixe (position: fixed) est complètement retiré du flux normal du document et est positionné de manière absolue par rapport à la fenêtre du navigateur (viewport) et un élément adhérent (position: sticky) commence dans le flux normal du document (comme un élément avec position: relative), mais il peut devenir "fixé" (collé) lorsque l'utilisateur fait défiler la page et que l'élément atteint une certaine position définie (généralement un certain seuil par rapport à l'élément parent).

Différentes valeurs de la propriété position
Information

La propriété position: unset réinitialise la propriété afin que sa valeur soit la valeur héritée depuis l'élément parent, ou soit la valeur initiale (s'il n'y a pas d'héritage).

Positionnement flottant (float: left; ou float: right;) :

Le positionnement flottant permet de modifier le positionnement statique des éléments pour "faire flotter" les éléments à gauche float: left; ou à droite float:right;.

Dans l'exemple suivant, l'image est positionnée à gauche.

Le CSS : L'affichage :
div#header {
    color: maroon;
    font-family: sans-serif;
    border-bottom: 1px solid black;
}
div#footer {
    color: black;
    clear: left;
}
div#texte {
    margin-left: 25%;
}
div#image {
    background-color: red;
    float: left;
    width: 20%;
}
saisie écran encadrement

Dans cet exemple,

  • La propriété float: left; de l'élément image indique que l'élément doit être flottant à une gauche et placé hors du flux normal; il est important de lui donner une dimension grâce à la propriété width: 20%; pour lui fixer une taille fixe, en rapport avec l'élément voisin.
  • La propriété margin-left: 25%; de l'élément texte est nécessaire pour permettre à l'élément flottant de trouver sa place à gauche de l'entièreté du texte.
  • La propriété clear: left; de l'élément footer signifie que l'élément reprend un position normale dans le flux.

En gros, l'utilisation de float: left; permet de retirer un élément du flux normal et ne sera aujourd'hui utilisé que pour placer un élément à gauche ou à droite avec les autres éléments "inline" qui se placent autour (imahe d'illustration dans un article par exemple).

Gérer le chevauchement avec la propriété z-index :

Vous l'avez remarqué, les éléments positionnés en absolu sont placés par-dessus le reste des éléments de la page. Mais si vous placez deux éléments en absolu aux mêmes coordonnées... ils vont se chevaucher.

Dans ce cas, vous pouvez utiliser la propriété z-index pour indiquer quel élément doit apparaître au-dessus des autres : vous empilez vos éléments dans l'ordre souhaité ! L'élément ayant la valeur de z-index la plus élevée sera placé par-dessus les autres.

Si j'écris le HTML associé au CSS suivant :

<div class="conteneur">
    <div class="box une">Élément 1</div>
    <div class="box deux">Élément 2</div>
    <div class="box trois">Élément 3</div>
</div>
* {
    font-family: Arial;
}

.box {
    background-color: #FFF;
    border-radius: 10px;
    border: 3px solid black;
    height: 150px;
    width: 150px;
    display: flex;
    justify-content: center;
    align-item: center;
}

.conteneur {
    position: relative;
    height: 300px;
    width: 300px;
}

.une {
    background-color: #C2B0F9;
    position: absolute;
    left: 0;
    top: 90px;
    z-index: 1;
}

.deux {
    background-color: #CBFCB9;
    position: absolute;
    right; 70px;
    top: 0;
    z-index: 2;
}

.trois {
    background-color: #F2A3BB;
    position: absolute;
    right: 0;
    bottom: 20px;
    z-index: 3;
}

On obtient :

Des éléments qui se chevauchent

Display :

En HTML5, nous retrouvons le typage d'éléments HTML en ligne et en bloc comme expliqué ci-dessus mais également d'autres typages que voici :

  • none : l'élément n'est pas affiché.
  • inline : l'élément est affiché en ligne.
  • block : l'élément est affiché en bloc.
  • inline-block : l'élément est affiché en ligne mais peut être redimensionné (width, height) comme un bloc.
  • list-item : l'élément est affiché en élément de liste (ex : <li>).
  • table : l'élément estaffiché comme une table (ex : <table>).
  • flex : l'élément est affiché comme élément flexible (voir ci-dessous).
  • grid : l'élément est affiché comme une grille (voir ci-desous).

Parmi tous les positionnements présentés ici, les trois positionnements les plus utilisés sont le inline-block et surtout le positionnement flex et/ou grid qui nous facilite grandement la tâche.

Positionnement inline-block :

Les manipulations que demande le positionnement flottant se révèlent parfois un peu délicates sur des sites complexes. Dès qu'il y a un peu plus qu'un simple menu à mettre en page, on risque d'avoir à recourir à des clear qui complexifient rapidement le code de la page. Imaginez que vous voulez réaliser une mise en page du type "menu à gauche suivi d'une partie centrale" (exactement comme la mise en page de ce syllabus). Dans ce cas, le positionnement inline-block convient parfaitement car :

  • Les éléments vont se positionner les uns à côté des autres (exactement ce qu'on veut pour placer notre menu et le corps de notre page !).
  • On peut leur donner des dimensions précises (là encore, exactement ce qu'on veut !).

Positionnement flex :

Important

Prenez la peine de découvrir et tester ce positionnement ! Vous pouvez facilement vous passer des autres positionnements mais pas de celui-ci.

Le dernier venu en terme de positionnement est le position flex. Celui-ci simplifie vraiment le positionnement de zones HTML.

Son principe est le suivant :

  1. Vous définissez un conteneur.
  2. Vous placez différents éléments à l'intérieur du conteneur.
  3. Vous renseignez à flex comment positionner ces éléments à l'intérieur du conteneur.

Imaginez un carton dans lequel vous rangez plusieurs objets : c'est le principe !

Sur une même page web, vous pouvez avoir plusieurs conteneurs (plusieurs cartons, si vous préférez). Vous pouvez en créer autant que nécessaire pour obtenir la mise en page que vous voulez.

Information

Un conteneur (container en anglais) est une balise qui peut renfermer d'autres balises, comme du texte ou encore des images. Les conteneurs les plus célèbres sont les balises <div> et <span>.

Exemple :

Le code : L'affichage :
<section id="monconteneur">
    <article>Élément 1</article>
    <article>Élément 2</article>
    <article>Élément 3</article>
</section>

#conteneur {
    display: flex;
}

Image issue de Open Classroom.

Quelques propriétés flex intéressantes :

  • flex-direction: column/row pour positionner les éléments verticalement (en colonne) ou horizontalement (en ligne, par défaut).

    Il existe également flex-direction: row-reverse/column-reverse qui organise les éléments sur une ligne ou une colonne, mais en ordre inversé.

  • justify-content: flex-start/flex-end/space-around/space-between/center pour aligner les éléments sur l'axe principal (horizontalement le plus plus souvent).

    Pour la valeur space-between, les éléments sont étirés sur tout l'axe (il y a de l'espace entre eux).

    Pour la valeur space-around, c'est la même chose, c'est-à-dire que les éléments sont étirés sur tout l'axe, mais ils laissent aussi de l'espace sur les extrémités.

  • align-items: center/stretch/flex-start/flex-end/baseline pour aligner les éléments sur l'axe secondaire (verticalement).

    La valeur stretch est la valeur par défaut qui pemet aux éléments d'être étiré sur tout l'axe.

    La valeur baseline permet aux éléments d'être aligné sur la ligne de base, ce qui est semblable à la valeur flex-start.

  • Par défaut, les blocs essaient de rester sur la même ligne s'ils n'ont pas la place, quitte à "s'écraser", et provoquer parfois des anomalies dans la mise en page (certains éléments pouvant dépasser de leur conteneur). Si vous voulez, vous pouvez demander à ce que les blocs à la ligne lorsqu'ils n'ont plus la place, avec la propriété flex-wrap dont voici les différentes valeurs :

    • nowrap : pas de retour à la ligne (par défaut);

    • wrap : les éléments vont à la ligne lorsqu'il n'y a plus la place;

    • wrap-reverse : les éléments vont à la ligne, lorsqu'il n'y a plus la place, en sens inverse.

  • Si vous avez plusieurs lignes dans votre Flexbox, vous pouvez choisir comment celles-ci seront réparties avec la propriété align-content.

    Important

    Cette propriété n'a aucun effet s'il n'y a qu'une seule ligne dans la Flexbox.

    Prenons donc un cas de figure où nous avons plusieurs lignes. J'autorise les éléments à aller à la ligne avec flex-wrap.

    Voyons voir comment les lignes se répartissent différemment avec la nouvelle propriété align-content que je voulais vous présenter. Elle peut prendre ces valeurs :

    • stretch (par défaut) : les éléments s'étirent pour occuper tout l'espace;

    • flex-start : les éléments sont placés au début;

    • flex-end : les éléments sont placés à la fin;

    • center : les éléments sont placés au centre;

    • span-between : les éléments sont séparés avec de l'espace entre eux;

    • space-around : c'est la même chose, mais il y a aussi de l'espace au début et à la fin.

Important

Plus d'informations à ce sujet sur le site d'Open Classroom : Positionnement flex.

En gros, le display: flex permet de changer la disposition des élémentsavec un positionnementen ligne ou en colonne. Les éléments enfants d'une Flexbox ont alors la responsabilité de définir leur largeur/hauteur via les propriétés width/height via le flex-basis.

L'approche flexbox est donc utile pour changer la direction de placement des éléments (pour par exemple les placer les uns à côté des autres) sans forcément avoir de dimensions précises pour les enfants. On aura donc tendance à les utiliser dans les cas suivants :

  • On veut aligner les éléments verticalement ou horizontalement en insérant un espace avec la propriété gap.

    Par exemple, si vous voulez garder les mêmes distances entre les rangées et les colonnes sans avoir à vous compliquer la vie, vous précisez simplement une valeur.

  • On a une grille qui n'est pas uniforme (structure des colonnes qui varient entre chaque ligne).

Information

Et si vous voulez vous entraîner pour vous assurer que vous maîtrisez bien les propriétés de Flexbox, je vous recommande le jeu Flexbox Froggy. Avec les différentes propriétés, vous devrez replacer les grenouilles sur les nénuphars.

Grid :

De la même manière que pour Flexbox, lorsque vous utilisez CSS Grids, vous pouvez imaginer un conteneur, une sorte de "carton" dans lequel vous allez mettre les éléments de votre grid. Sauf que, cette fois-ci, vous allez avoir besoin de déclarer la propriété display: grid; :

.conteneur {
    display: grid;
}

Ensuite, il faut préciser quelques éléments supplémentaires si on veut que ça fonctionne. Pour ce faire, il s'agit de se demander comment représenter nos éléments. Lorsque vous créez un tableau, vous réfléchissez aux colonnes et aux rangées qu'il faudra créer. Eh bien, c'est la même chose ici !

La grosse particularité du display: grid est le fait que l'élément parent a la responsabilité de définir la structure via un grid-template-columns ou grid-template-rows. Cela permet de ne pas avoir à ajouter des règles sur les éléments enfants.

Information

Jusqu'à maintenant, nous avons utilisé une unité en px pour définir les hauteurs et largeurs des rangées et colonnes. Mais il est égalemnt possible d'utiliser des em, rem, et des pourcentages.

Et encore mieux : je vais vous montrer une unité qui est spécifique aux grids : les "fraction units", ou fr pour les intimes, qui représentent des parts de largeur dans les colonnes.

Si vous tentez d'utiliser des pourcentages avec CSS Grid, vous verrez que ce n'est pas toujours simple. Si par exemple, vous souhaitez créer 2 colones dans une grid, et que vous mettez 50% de largeur pour chacune d'entre elles, vous vous attendez sûrement à ce que votre grid prenne toute la largeur... Et pourtant non : les grid gaps (les espacements entre vos grids) peuvent venir mettre le bazar dans tout ça, et votre grid va dépasser. C'est pourquoi il est encore plus simple d'utiliser des fr, l'unité créée spécialement pour les CSS Grids.

Typiquement, comme son nom l'indique, ce type de positionnement est très adapté à une disposition en grille.

.grid {
    display: grid;
    gap: 10px;
    grid-template-columns: repeat(5, 1fr);
}

On peut aussi facilement créer une structure responsive qui adapte le nombre d'élément en fonction de la largeur souhaité pour les éléments.

.grid {
    display: grid;
    gap: 10px;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

On peut aussi utiliser ce type de disposition pour créer des structures de page rapidement grâce notamment au grid-area.

<style>
.layout {
    display: grid;
    min-height: 100vh;
    grid-template: "header header" min-content
                   "sidebar main" 1fr
                   "footer footer" min-content;
    grid-template-columns: 250px 1fr;
}
header {
    grid-area: header;
}
aside {
    grid-area: sidebar;
}
main {
    grid-area: main;
}
footer {
    grid-area: footer;
}
</style>
<div class="layout">
    <header>Header</header>
    <aside>Sidebar</aside>
    <main>Contenu</main>
    <footer>Footer</footer>
</div>

Cette approche permet de piloter facilement la structure depuis l'élément parent .layout en changeant le template via la propriété grid-template. Ce type de positionnement est donc intéressant pour les cas suivants :

  • On souhaite utiliser une grille simple.
  • On veut créer une structure qui peut être décomposer sous forme de colonnes (constantes entre chaque ligne).

En résumé, l'avantage d'utiliser des grilles CSS et des media queries pour faire la mise en page plutôt que d'utiliser un framework de type Bootstrap est multiple. Non seulement cela est plus green puisqu'il n'est pas nécessaire de charger le framework, mais cela permet de mieux séparer le font et la forme. Finie la litanie de classes associées à nos balises qui pollue le code HTML (exemple : <div class="col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2 col-xxl-1>). La mise en forme avec les grilles est intégralement gérée dans des fichiers CSS.

Exemple de fichier HTML :

<!DOCTYPE html>
<html lang="fr">
    <head>
        <title>Page de test avec une disposition utilisant une grille</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <link href="grid.css" rel="stylesheet">
        <meta name="description" content="Comment créer une page responsive sans utiliser de framework CSS">
    </head>
    <body>
        <header>
            partie en-tête...
        </header>
        <main>
            <article>
                <h1>Comment créer une page responsive sans utiliser de framework CSS</h1>
                <p>
                    Avec la propriété CSS Grid et des média queries !
                </p>
                <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Ipsum quis sed voluptas maxime voluptatibus illo deserunt temporibus pariatur accusantium commodi quidem similique rem natus nostrum odit officiis blanditiis reprehenderit, fugiat, sequi placeat error harum amet eligendi voluptate! Quasi nisi facilis praesentium est ex consectetur placeat corrupti quas voluptatem, quis id.</p>
                <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eveniet est facilis harum nisi quo architecto doloremque, voluptate qui dolor porro, autem ab reprehenderit ducimus neque sint nobis ipsam recusandae odit, sequi nihil expedita. Eligendi itaque amet odio quisquam similique obcaecati!</p>
                <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Vero corporis voluptates atque, quos dignissimos dicta quod vitae! Enim at pariatur quae expedita sed hic perferendis mollitia autem, voluptates, sint dolorem?</p>
            </article>
        </main>
        <aside>
            partie complément...
        </aside>
        <footer>
            partie pied de page...
        </footer>
    </body>
</html>

Le fichier CSS associé :

body {
    background-color: #e06ed1;
    display: grid;
    margin: 0;
    grid-template-columns: 1fr;
    grid-template-areas:
        "entete"
        "contenu"
        "complements"
        "piedPage";
    grid-template-rows: 100px 1fr 100px 100px;
}
@media (min-width: 576px) {
    body {
        grid-gap: 10px;
        grid-template-columns: 1fr 250px;
    }
}
@media (min-width: 768px) {
    body {
        grid-template-columns: 742px 250px;
        justify-content: center;
    }
}
header, main, aside, footer {
    padding: 10px;
}
header {
    grid-area: entete;
    background-color: #bfe966;
}
main {
    grid-area: contenu;
    overflow-y: auto;
    background-color: lavander;
}
aside {
    grid-area: complements;
    background-color: mediumturquoise;
}
footer {
    grid-area: piedPage;
    background-color: #ebb2b2;
}

Dans cet exemple, le fichier HTML ne conient aucun élément placé spécifiquement pour effectuer la mise en page. C'est uniquement dans le fichier CSS que la mise en page est effectuée.

Remarque : les couleurs de fond des différentes zones n'ont été ajoutées que pour les rendre plus visibles !

Les quatre grandes parties de la page (<header>, <main>, <aside> et <footer>) ont été définies comme des zones pour la grille (entete, contenu, complements et piedPage). Par défaut, pour les écrans de petite taille, ces quatre zones sont disposées les unes au-dessous des autres grâce à la propriété grid-template-areas.

Lorsque l'écran est un peu plus grand (plus que 576 pixels de large), cette propriété est redéfinie pour obtenir sur une première ligne l'en-tête, sur une seconde ligne le contenu principal, sur le côté le complément, et le pied de page sur une dernière ligne. Afin d'avoir toujours ces éléments-là visibles et d'éviter un ascenseur vertical sur l'ensemble de la page, la propriété height a été définie à 100 vh, c'est-à-dire toute la hauteur de l'écran, et le débordement éventuel de la partie principale a été géré avec la propriété overflow-y à auto.

Pour les écrans encore un peu plus grands (768 pixels de large au minimum), des gouttières sont ajoutées entre les zones et la partie complément est élargie.

Enfin, sur la version pour les grands écrans (largeur minimale de 992 pixels), la largeur des deux colonnes est figée pour que les lignes ne soient pas trop longues et des marges sont positionnées sur les côtés.