Introduction au Développement HTML et CSS
Introduction au Développement HTML et CSS

Techniques d'adaptabilité (unités %, vh/vw, em/rem)

Introduction à l'Adaptabilité Web

Dans le monde numérique actuel, les utilisateurs accèdent aux sites web depuis une multitude d'appareils : ordinateurs de bureau, ordinateurs portables, tablettes, smartphones, et même des téléviseurs connectés. Chacun de ces appareils possède des tailles d'écran et des résolutions différentes. Pour offrir une expérience utilisateur optimale, il est crucial que nos sites web s'adaptent et s'affichent correctement, quel que soit l'écran. C'est ce que l'on appelle le Web Adaptatif ou Responsive Web Design.

Traditionnellement, les développeurs utilisaient des unités de mesure absolues comme les pixels (px). Bien que les pixels soient précis, ils ne s'adaptent pas. Un élément de 200px aura toujours la même taille physique, peu importe la taille de l'écran, ce qui peut entraîner des problèmes de mise en page sur de petits appareils.

Pour relever ce défi, CSS propose des unités de mesure relatives. Ces unités se basent sur un contexte donné (la taille du parent, la taille de la police racine, ou la taille de la fenêtre de visualisation) et s'ajustent dynamiquement. Dans cette leçon, nous allons explorer les unités relatives les plus fondamentantes pour l'adaptabilité : les pourcentages (%), les unités de viewport (vh/vw), et les unités relatives à la taille de police (em/rem).

Les Unités CSS pour l'Adaptabilité

Les unités de mesure CSS peuvent être classées en deux catégories principales :

  • Unités Absolues : Leur valeur est fixe et ne change pas, quelle que soit la taille de l'écran ou de l'élément parent. L'exemple le plus courant est le pixel (px).
  • Unités Relatives : Leur valeur est calculée en fonction d'un autre élément ou d'une autre propriété. Elles sont la clé de la conception adaptative.

Nous allons nous concentrer sur les unités relatives.

1. Les Pourcentages (%)

Le pourcentage (%) est l'une des unités relatives les plus anciennes et les plus utilisées en CSS. Sa valeur est toujours relative à une autre valeur. Le contexte de référence dépend de la propriété CSS à laquelle il est appliqué.

  • Pour les propriétés de dimension (width, height, padding, margin) : Le pourcentage est relatif à la dimension correspondante de l'élément parent.
  • Pour les propriétés de taille de police (font-size) : Le pourcentage est relatif à la taille de police calculée de l'élément parent.

Avantages :

  • Fluidité : Permet de créer des mises en page fluides qui s'étirent ou se contractent en fonction de la taille de l'élément conteneur.
  • Simplicité : Relativement facile à comprendre et à utiliser pour des mises en page de base.

Inconvénients :

  • Dépendance au parent : La taille d'un élément peut devenir imprévisible si la structure HTML est complexe et que les parents ont des tailles fluctuantes.
  • Empilement : Pour certaines propriétés (comme font-size), les pourcentages s'empilent, ce qui peut rendre le calcul difficile.

Exemple de Code : Utilisation des Pourcentages pour la Mise en Page

Cet exemple montre comment utiliser les pourcentages pour créer une disposition de colonne fluide.

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Exemple Pourcentages</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f4f4f4;
        }
        .conteneur {
            width: 90%; /* Le conteneur prend 90% de la largeur du body */
            margin: 0 auto; /* Centre le conteneur */
            background-color: #fff;
            padding: 20px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
            display: flex; /* Utilisation de Flexbox pour les colonnes */
            flex-wrap: wrap; /* Permet aux colonnes de passer à la ligne */
        }
        .colonne {
            width: 48%; /* Chaque colonne prend 48% de la largeur du conteneur */
            margin: 1%; /* Marge de 1% pour créer un espace entre les colonnes */
            padding: 15px;
            background-color: #e0f7fa;
            border: 1px solid #b2ebf2;
            box-sizing: border-box; /* Inclut padding et border dans la largeur */
        }
        /* Media Query pour les petits écrans */
        @media (max-width: 600px) {
            .colonne {
                width: 98%; /* Sur petits écrans, chaque colonne prend presque toute la largeur */
                margin: 1% auto;
            }
        }
    </style>
</head>
<body>
    <div class="conteneur">
        <div class="colonne">
            <h3>Colonne 1</h3>
            <p>Ce texte est dans la première colonne. Sa largeur est définie en pourcentage par rapport au conteneur parent.</p>
        </div>
        <div class="colonne">
            <h3>Colonne 2</h3>
            <p>Ce texte est dans la deuxième colonne. La mise en page s'adapte lorsque la fenêtre est redimensionnée.</p>
        </div>
    </div>
</body>
</html>

Explication du code :

  • Le .conteneur prend 90% de la largeur du body. Si la fenêtre du navigateur mesure 1000px, le conteneur aura 900px de large.
  • Chaque .colonne prend 48% de la largeur du .conteneur. Si le conteneur fait 900px, chaque colonne fera 432px. La margin de 1% contribue à l'espacement.
  • Avec une media query, nous modifions la largeur des .colonne à 98% sur les écrans plus petits que 600px, les faisant occuper presque toute la largeur disponible et s'empiler verticalement.

2. Les Unités de Viewport (vh, vw, vmin, vmax)

Les unités de viewport sont relatives à la taille de la fenêtre de visualisation (viewport) du navigateur. Elles sont particulièrement utiles pour créer des éléments qui doivent s'adapter directement à la taille de l'écran de l'utilisateur, et non à un élément parent.

  • vw (viewport width) : 1vw est égal à 1% de la largeur du viewport.
  • vh (viewport height) : 1vh est égal à 1% de la hauteur du viewport.
  • vmin (viewport minimum) : 1vmin est égal à 1% de la plus petite dimension du viewport (largeur ou hauteur).
  • vmax (viewport maximum) : 1vmax est égal à 1% de la plus grande dimension du viewport (largeur ou hauteur).

Avantages :

  • Contrôle direct sur la taille du viewport : Idéal pour les sections "full screen" ou les éléments qui doivent toujours occuper une certaine proportion de l'écran.
  • Typographie réactive : Peut être utilisé pour des tailles de police qui s'adaptent directement à la taille de l'écran, offrant une lecture confortable quelle que soit la résolution.

Inconvénients :

  • Peut être trop sensible : Un petit changement dans la taille du viewport peut entraîner des changements significatifs dans la taille des éléments, parfois indésirables.
  • Problèmes de défilement : Pour les height, l'utilisation exclusive de vh peut entraîner un défilement non désiré si le contenu dépasse la hauteur du viewport.
  • Barres de défilement : Les barres de défilement peuvent affecter la largeur du vw sur certains navigateurs, mais c'est un problème moins courant aujourd'hui.

Exemple de Code : Utilisation de vh et vw

Cet exemple montre comment créer une section d'en-tête (hero section) qui occupe toujours 100% de la hauteur du viewport et comment ajuster la taille de la police en fonction de la largeur du viewport.

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Exemple Viewport Units</title>
    <style>
        body {
            margin: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            overflow-x: hidden; /* Empêche le défilement horizontal */
        }
        .hero-section {
            height: 100vh; /* La section prend 100% de la hauteur du viewport */
            width: 100vw; /* La section prend 100% de la largeur du viewport */
            background-color: #26a69a;
            color: white;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            text-align: center;
        }
        .hero-title {
            font-size: 8vw; /* La taille du titre est 8% de la largeur du viewport */
            margin-bottom: 20px;
        }
        .hero-subtitle {
            font-size: 3.5vw; /* La taille du sous-titre est 3.5% de la largeur du viewport */
            max-width: 80vw; /* Limite la largeur du texte pour éviter le débordement */
        }
        .content-below {
            padding: 50px;
            background-color: #f0f0f0;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="hero-section">
        <h1 class="hero-title">Bienvenue sur Notre Site !</h1>
        <p class="hero-subtitle">Découvrez des techniques d'adaptabilité web pour des expériences utilisateur parfaites.</p>
    </div>
    <div class="content-below">
        <h2>Contenu en dessous</h2>
        <p>Ce contenu est un exemple de ce qui pourrait suivre la section "hero". Notez que la section au-dessus s'adapte parfaitement à la taille de votre fenêtre.</p>
        <p>Redimensionnez votre navigateur pour voir l'effet des unités `vh` et `vw` sur le titre et la section entière.</p>
    </div>
</body>
</html>

Explication du code :

  • Le .hero-section utilise height: 100vh; et width: 100vw; pour s'assurer qu'il occupe toujours la totalité de la surface visible de l'écran, créant un effet "plein écran".
  • Les tailles de police .hero-title et .hero-subtitle sont définies avec vw. Cela signifie que plus la largeur de la fenêtre du navigateur est grande, plus le texte sera grand, et inversement. C'est une technique puissante pour une typographie vraiment réactive.

3. Les Unités Relatives à la Taille de Police (em, rem)

Ces unités sont fondamentales pour une gestion cohérente et adaptable de la typographie et de l'espacement.

3.1. em

L'unité em est relative à la taille de police de l'élément parent. Si un élément a une taille de police de 16px, alors 1em dans cet élément sera égal à 16px. Si un enfant de cet élément a sa propre taille de police définie, alors les em de cet enfant seront basés sur sa propre taille de police.

  • Comportement : Relative à la font-size de l'élément parent.
  • Utilisation : Utile pour les composants où l'espacement et les tailles sont relatifs à la taille de police locale du composant.

Avantages :

  • Flexibilité locale : Permet de dimensionner des éléments ou des espacements en fonction de la taille de police d'un conteneur spécifique, ce qui est utile pour les modules ou widgets.
  • Scalabilité : Si la taille de police du parent est modifiée, tous les em à l'intérieur s'adaptent proportionnellement.

Inconvénients :

  • Effet composé (compounding effect) : Si vous avez des éléments imbriqués avec des tailles de police définies en em, la taille finale peut devenir imprévisible et difficile à calculer, car elle dépend d'une chaîne de parents.
  • Maintenance : Difficile à déboguer si les tailles ne sont pas celles attendues en raison de l'héritage.

3.2. rem

L'unité rem (root em) est relative à la taille de police de l'élément racine (le html). C'est la plus prévisible des deux car elle a un point de référence unique et constant.

  • Comportement : Relative à la font-size de l'élément html.
  • Utilisation : Idéale pour définir une base typographique globale et pour l'espacement (padding, margin) afin de maintenir une cohérence verticale sur l'ensemble du site.

Avantages :

  • Prévisibilité : Toujours basé sur la taille de police de l'élément html, ce qui élimine l'effet composé et rend les calculs plus simples.
  • Scalabilité globale : En ajustant une seule propriété (font-size sur html), vous pouvez redimensionner proportionnellement l'ensemble de la typographie et de l'espacement de votre site. C'est excellent pour l'accessibilité (permettre aux utilisateurs de zoomer facilement le texte).
  • Maintenance : Plus facile à gérer et à déboguer.

Inconvénients :

  • Moins de flexibilité locale : Pour certains composants très spécifiques, un em pourrait être plus intuitif si la taille doit vraiment dépendre d'un parent direct et non de la racine.

Exemple de Code : Utilisation de em et rem

Cet exemple illustre comment em et rem fonctionnent, en définissant une taille de police de base sur html et en montrant l'héritage et l'utilisation.

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Exemple EM et REM</title>
    <style>
        /* Définit une taille de police de base sur l'élément racine (html) */
        html {
            font-size: 16px; /* Taille de police par défaut de 1rem = 16px */
        }
        body {
            font-family: 'Open Sans', sans-serif;
            margin: 2rem; /* Marge autour du body, 2 * 16px = 32px */
            background-color: #f9f9f9;
            color: #333;
        }

        /* Utilisation de REM pour les titres et paragraphes principaux */
        h1 {
            font-size: 3rem; /* 3 * 16px = 48px */
            margin-bottom: 1.5rem; /* 1.5 * 16px = 24px */
            color: #007bff;
        }
        p {
            font-size: 1rem; /* 1 * 16px = 16px */
            line-height: 1.6;
            margin-bottom: 1rem;
        }

        /* Conteneur avec une taille de police modifiée pour montrer l'effet de EM */
        .card {
            background-color: #ffffff;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 1.5rem; /* Padding basé sur la font-size de html (1.5 * 16px = 24px) */
            margin-bottom: 2rem;
            box-shadow: 0 4px 8px rgba(0,0,0,0.05);
        }

        .card-title {
            font-size: 1.5rem; /* Toujours 1.5 * 16px = 24px, car basé sur html */
            color: #28a745;
            margin-bottom: 0.5rem;
        }

        .nested-element {
            font-size: 0.8em; /* 0.8 * (font-size du parent, ici .card) = 0.8 * 24px = 19.2px. C'est une erreur! */
            /* Non, le .card n'a pas de font-size définie, donc elle hérite de 1rem = 16px. */
            /* Donc 0.8em ici sera 0.8 * 16px = 12.8px */
            /* Pour montrer l'effet composé, ajoutons une font-size au .card */
            /* Correction: Pour que l'effet em soit clair, .card doit avoir sa propre font-size */
            /* Supposons que .card n'a pas de font-size explicitement définie, elle hérite de body (1rem = 16px) */
            /* Donc 0.8em pour .nested-element sera 0.8 * 16px = 12.8px */
        }

        /* Modifier la taille de police du .card pour illustrer l'em */
        .card.special {
            font-size: 18px; /* Taille de police du parent est maintenant 18px */
        }
        .card.special .nested-element-em {
            font-size: 1.2em; /* 1.2 * (font-size du parent .card.special = 18px) = 21.6px */
            color: #dc3545;
            font-weight: bold;
        }
        .card.special .nested-element-rem {
            font-size: 1.2rem; /* 1.2 * (font-size de html = 16px) = 19.2px */
            color: #ffc107;
        }

        /* Astuce pour les utilisateurs : Changer la taille de police de base pour un zoom facile */
        /*
        @media (min-width: 1200px) {
            html {
                font-size: 18px; // Plus grand sur de grands écrans
            }
        }
        @media (max-width: 768px) {
            html {
                font-size: 14px; // Plus petit sur de petits écrans
            }
        }
        */
    </style>
</head>
<body>
    <h1>Titre Principal (3rem)</h1>
    <p>Ceci est un paragraphe de texte. Sa taille est définie en `rem`, ce qui signifie qu'elle est relative à la taille de police de l'élément HTML racine. Si la taille de police de `html` change, ce texte s'adaptera proportionnellement.</p>

    <div class="card">
        <h2 class="card-title">Titre de Carte (1.5rem)</h2>
        <p>Le padding de cette carte est défini en `rem`. Son texte est également en `rem`. Cela assure une cohérence et une adaptabilité facile à l'échelle globale du site.</p>
    </div>

    <div class="card special">
        <h2 class="card-title">Carte Spéciale (font-size: 18px)</h2>
        <p>Cette carte a sa propre *taille de police parent* définie à `18px`. Voyez comment les unités `em` et `rem` réagissent différemment à l'intérieur :</p>
        <p class="nested-element-em">
            Ceci est un paragraphe avec une taille de police de `1.2em`. Sa taille est basée sur la taille de police de la *carte parente* (18px * 1.2 = 21.6px).
        </p>
        <p class="nested-element-rem">
            Ceci est un paragraphe avec une taille de police de `1.2rem`. Sa taille est toujours basée sur la taille de police de l'élément *racine* HTML (16px * 1.2 = 19.2px).
        </p>
    </div>
</body>
</html>

Explication du code :

  • html { font-size: 16px; } : Nous définissons une taille de police de base de 16px pour l'élément racine. Cela signifie que 1rem équivaut à 16px partout sur le site.
  • h1 { font-size: 3rem; } : Le titre h1 aura une taille de 3 * 16px = 48px.
  • .card { padding: 1.5rem; } : Le padding de la carte sera de 1.5 * 16px = 24px sur tous les côtés.
  • Dans la .card.special :
    • La font-size du parent .card.special est explicitement définie à 18px.
    • .nested-element-em : Sa font-size est 1.2em. Comme son parent (.card.special) a une font-size de 18px, la taille réelle sera 1.2 * 18px = 21.6px. C'est l'exemple parfait où em dépend du parent direct.
    • .nested-element-rem : Sa font-size est 1.2rem. Peu importe la font-size de son parent, elle est toujours basée sur la font-size de l'élément html (qui est 16px). Donc, la taille réelle sera 1.2 * 16px = 19.2px.

Cet exemple met en évidence la différence fondamentale et l'avantage de la prévisibilité de rem par rapport à em pour la gestion globale de la typographie et de l'espacement.

Quand Utiliser Quelle Unité ? (Résumé)

Le choix de l'unité dépend de l'objectif et du contexte. Voici quelques lignes directrices générales :

  • px (pixels) :

    • Utilisation : Pour les éléments qui doivent avoir une taille absolument fixe et précise (ex: bordures de 1px, ombres portées avec un décalage fixe), ou si vous n'avez pas besoin d'adaptabilité pour cet élément précis.
    • Avantages : Précision, pas de complexité liée à l'héritage.
    • Inconvénients : Non adaptatif, peut créer des problèmes sur différentes tailles d'écran.
  • % (pourcentages) :

    • Utilisation : Idéal pour les largeurs et hauteurs d'éléments qui doivent remplir une proportion de leur conteneur parent (par exemple, des colonnes dans une grille fluide). Utile pour des espacements (padding/margin) qui doivent s'adapter au conteneur.
    • Avantages : Fluidité des mises en page.
    • Inconvénients : Peut devenir complexe avec l'imbrication profonde, dépendance forte au parent.
  • vh, vw (unités de viewport) :

    • Utilisation : Pour les éléments qui doivent s'adapter directement à la taille de la fenêtre du navigateur, comme les sections "hero" en plein écran, ou pour une typographie qui doit toujours être proportionnelle à la largeur de l'écran.
    • Avantages : Contrôle direct de la taille de l'écran, puissant pour les effets visuels globaux.
    • Inconvénients : Sensible aux petits changements du viewport, peut entraîner des barres de défilement indésirables si mal utilisé pour la hauteur.
  • rem (root em) :

    • Utilisation : Recommandé pour la majorité des tailles de police (font-size), des marges (margin) et des espacements (padding) sur l'ensemble du site. Permet une échelle globale cohérente et facilite l'accessibilité.
    • Avantages : Prévisibilité, scalabilité globale via un seul point de contrôle (html), excellent pour l'accessibilité.
    • Inconvénients : Moins adapté pour des contextes où la taille doit spécifiquement dépendre d'un parent direct non racine.
  • em :

    • Utilisation : Principalement pour l'espacement ou les tailles d'éléments à l'intérieur de composants spécifiques où vous voulez que ces valeurs soient relatives à la taille de police du composant lui-même, plutôt qu'à la taille de police globale du document.
    • Avantages : Flexibilité locale, permet de créer des composants autonomes.
    • Inconvénients : Problèmes d'imbrication (effet composé), difficile à déboguer si le comportement n'est pas clair.

Conclusion

Maîtriser les unités de mesure relatives est une compétence essentielle pour tout développeur web moderne. Elles sont le pilier du Responsive Web Design, permettant à vos créations de s'adapter gracieusement à n'importe quel appareil et d'offrir une expérience utilisateur optimale.

En utilisant intelligemment les pourcentages pour les largeurs fluides, les unités de viewport pour les sections liées à l'écran, et surtout les rem pour une typographie et un espacement cohérents et accessibles, vous construirez des interfaces web robustes, flexibles et agréables à utiliser. Pratiquez avec ces unités, expérimentez en redimensionnant votre navigateur, et vous développerez rapidement une intuition sur la meilleure unité à utiliser dans chaque situation.