📚 Cours SCSS (Sass) 📍 Chapitre 12 / 21

Chapitre 12 – Maps SCSS

Les maps SCSS sont l'un des outils les plus "pro" de Sass. Elles permettent de stocker des données sous forme clé → valeur (comme un dictionnaire), puis de les exploiter avec des fonctions et des boucles. Résultat : moins de @if répétitifs, plus de cohérence, et un SCSS plus facile à maintenir et à faire évoluer.

Objectifs du chapitre

  • Comprendre ce qu'est une map SCSS et comment elle se structure.
  • Savoir récupérer une valeur avec map-get().
  • Vérifier l'existence d'une clé avec map-has-key().
  • Parcourir une map avec @each pour générer du CSS automatiquement.
  • Mettre en place des cas d'usage professionnels : couleurs, tailles, breakpoints, thèmes.
À retenir

Une map, c'est une liste structurée : au lieu d'avoir juste des valeurs, tu as des clés (noms) qui pointent vers des valeurs. C'est comme un dictionnaire ou une table de correspondance.

Explications théoriques détaillées

Qu'est-ce qu'une map SCSS ?

Une map est une collection de paires (clé: valeur). Elle permet d'associer un nom sémantique à une valeur, ce qui rend ton code beaucoup plus lisible et maintenable.

Structure de base d'une map :

SCSS
$colors: (
  primary: #7aa7ff,
  success: #22c55e,
  warning: #f59e0b,
  danger:  #ef4444,
  muted:   #94a3b8
);

Ici, primary est une clé, et #7aa7ff est la valeur associée. On peut ensuite accéder à cette valeur de manière sémantique plutôt qu'en utilisant directement le code hexadécimal.

Pourquoi les maps sont utiles ?

Sans maps, tu finis souvent par écrire beaucoup de conditions répétitives pour mapper des noms vers des valeurs :

Exemple "moins propre" sans map :

SCSS
/* Beaucoup de conditions répétitives */
@mixin badge($type) {
  @if $type == success {
    background: #22c55e;
    color: white;
  } @else if $type == warning {
    background: #f59e0b;
    color: black;
  } @else if $type == danger {
    background: #ef4444;
    color: white;
  } @else {
    background: #7aa7ff;
    color: white;
  }
}

Avec une map, tu centralises les valeurs dans un seul endroit, puis tu les récupères proprement avec une simple fonction. C'est plus propre, plus maintenable, et plus facile à faire évoluer.

Conseil terrain

Les maps sont la base d'un design system SCSS : couleurs, typographie, espacements, breakpoints, thèmes… tout peut être structuré avec des maps pour créer un système cohérent et facile à maintenir.

Les fonctions clés à connaître

SCSS fournit plusieurs fonctions pour travailler avec les maps :

  • map-get($map, $key) : récupérer une valeur à partir de sa clé.
  • map-has-key($map, $key) : vérifier si une clé existe dans la map.
  • map-merge($map1, $map2) : fusionner deux maps en une seule.
  • map-keys($map) : obtenir la liste de toutes les clés.
  • map-values($map) : obtenir la liste de toutes les valeurs.
À retenir

Dans la pratique, map-get() et @each (pour parcourir les maps) sont les plus utilisés au quotidien. map-has-key() est essentiel pour éviter les erreurs avec des clés invalides.

Exemples simples

Récupérer une valeur avec map-get()

L'utilisation la plus basique : accéder à une valeur à partir de sa clé.

SCSS :

SCSS
$colors: (
  primary: #7aa7ff,
  danger:  #ef4444
);

.button {
  background: map-get($colors, primary);
  color: white;
  padding: 10px 16px;
  border-radius: 8px;
}

.button--danger {
  background: map-get($colors, danger);
}

CSS généré :

CSS
.button {
  background: #7aa7ff;
  color: white;
  padding: 10px 16px;
  border-radius: 8px;
}

.button--danger {
  background: #ef4444;
}

Vérifier une clé avec map-has-key()

Cette fonction est utile pour éviter des erreurs si on passe une clé incorrecte, et pour fournir une valeur par défaut.

SCSS :

SCSS
$colors: (
  primary: #7aa7ff,
  danger:  #ef4444
);

@function color($name) {
  @if map-has-key($colors, $name) {
    @return map-get($colors, $name);
  } @else {
    @return #7aa7ff; // Valeur par défaut (fallback)
  }
}

.alert {
  border-left: 4px solid color(danger);
  padding: 12px;
  background: rgba(color(danger), 0.1);
}

.alert--unknown {
  // Utilisation d'une clé qui n'existe pas
  border-left: 4px solid color(unknown); // Retourne #7aa7ff (fallback)
}
À retenir

Un fallback (valeur par défaut) rend ton SCSS plus robuste et évite les erreurs de compilation en cas de faute de frappe ou de clé manquante.

Parcourir une map avec @each

On peut générer des classes automatiquement en parcourant une map avec une boucle @each.

SCSS :

SCSS
$colors: (
  primary: #7aa7ff,
  success: #22c55e,
  warning: #f59e0b,
  danger:  #ef4444
);

@each $name, $value in $colors {
  .badge--#{$name} {
    background: $value;
    color: white;
    padding: 6px 10px;
    border-radius: 999px;
    font-size: 14px;
    font-weight: 600;
    display: inline-block;
  }
}

CSS généré (extrait) :

CSS
.badge--primary {
  background: #7aa7ff;
  color: white;
  padding: 6px 10px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  display: inline-block;
}

.badge--success {
  background: #22c55e;
  color: white;
  padding: 6px 10px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  display: inline-block;
}

/* ... et ainsi de suite pour warning et danger */

Exemples concrets et professionnels

Cas pro 1 : breakpoints (responsive) avec map

Plutôt que d'éparpiller des valeurs comme 768px, 1024px partout dans ton code, tu peux les centraliser dans une map.

SCSS :

SCSS
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 1024px,
  xl: 1280px,
  xxl: 1536px
);

@mixin mq($key) {
  @if map-has-key($breakpoints, $key) {
    @media (min-width: map-get($breakpoints, $key)) {
      @content;
    }
  } @else {
    @warn "Breakpoint inconnu : #{$key}. Utilisez sm, md, lg, xl ou xxl.";
  }
}

.container {
  padding: 16px;
  max-width: 100%;

  @include mq(md) {
    padding: 24px;
    max-width: 720px;
  }

  @include mq(lg) {
    padding: 32px;
    max-width: 960px;
  }

  @include mq(xl) {
    max-width: 1200px;
  }
}

CSS généré :

CSS
.container {
  padding: 16px;
  max-width: 100%;
}

@media (min-width: 768px) {
  .container {
    padding: 24px;
    max-width: 720px;
  }
}

@media (min-width: 1024px) {
  .container {
    padding: 32px;
    max-width: 960px;
  }
}

@media (min-width: 1280px) {
  .container {
    max-width: 1200px;
  }
}
Conseil terrain

Ce pattern (map + mixin responsive) est extrêmement courant dans les projets professionnels. Il évite des dizaines de répétitions de valeurs et rend les changements de breakpoints très faciles : un seul endroit à modifier.

Cas pro 2 : thèmes (dark / light) avec map imbriquée

Une map peut contenir d'autres maps. Cela permet de créer des structures complexes comme des systèmes de thèmes.

SCSS :

SCSS
$themes: (
  dark: (
    bg: #0b1020,
    text: #ffffff,
    card: rgba(255, 255, 255, 0.08),
    border: rgba(255, 255, 255, 0.12),
    accent: #7aa7ff
  ),
  light: (
    bg: #ffffff,
    text: #111827,
    card: rgba(17, 24, 39, 0.06),
    border: rgba(17, 24, 39, 0.12),
    accent: #3b82f6
  )
);

@function theme($mode, $token) {
  $theme-map: map-get($themes, $mode);
  
  @if map-has-key($theme-map, $token) {
    @return map-get($theme-map, $token);
  } @else {
    @warn "Token '#{$token}' non trouvé dans le thème '#{$mode}'";
    @return null;
  }
}

body {
  background: theme(dark, bg);
  color: theme(dark, text);
  font-family: 'Inter', sans-serif;
}

.card {
  background: theme(dark, card);
  border: 1px solid theme(dark, border);
  border-radius: 12px;
  padding: 20px;
}

.button {
  background: theme(dark, accent);
  color: white;
  padding: 10px 16px;
  border-radius: 8px;
}
À retenir

Ce type de structure est la base de nombreux systèmes de thèmes avancés. En changeant simplement dark en light dans la fonction theme(), tout ton design s'adapte automatiquement.

Cas pro 3 : remplacer les conditions répétitives

Au chapitre précédent, on utilisait des conditions pour gérer différentes tailles. Avec une map, c'est beaucoup plus élégant et maintenable.

SCSS (avec map) :

SCSS
$card-sizes: (
  sm: (
    padding: 12px,
    font-size: 14px,
    title-size: 16px
  ),
  md: (
    padding: 16px,
    font-size: 16px,
    title-size: 18px
  ),
  lg: (
    padding: 24px,
    font-size: 18px,
    title-size: 20px
  )
);

@each $size, $config in $card-sizes {
  .card--#{$size} {
    padding: map-get($config, padding);
    font-size: map-get($config, font-size);
    border: 1px solid #e2e8f0;
    border-radius: 12px;
    
    .card__title {
      font-size: map-get($config, title-size);
      font-weight: 700;
      margin-bottom: 12px;
    }
  }
}

CSS généré (pour .card--md) :

CSS
.card--md {
  padding: 16px;
  font-size: 16px;
  border: 1px solid #e2e8f0;
  border-radius: 12px;
}

.card--md .card__title {
  font-size: 18px;
  font-weight: 700;
  margin-bottom: 12px;
}
À retenir

Dès que tu vois une suite de @else if pour "mapper" une clé vers une valeur, c'est souvent un signal qu'une map serait plus adaptée. Les maps rendent ton code plus lisible, plus maintenable, et plus facile à étendre.

Bonnes pratiques

Guide des bonnes pratiques pour les maps SCSS

  • Centraliser tes maps "design" : crée un dossier settings/ ou config/ pour y mettre tes maps de couleurs, espacements, breakpoints, etc.
  • Utiliser des clés courtes et cohérentes : sm, md, lg, primary, secondary.
  • Créer des fonctions d'accès : comme color(), space(), bp() pour éviter d'écrire map-get() partout.
  • Toujours prévoir un fallback : ou utiliser @warn pour les clés invalides.
  • Documenter tes maps : explique ce que contient chaque map et comment l'utiliser.
  • Éviter les maps trop profondes : plus de 2 niveaux d'imbrication rendent le code difficile à lire.
À retenir

Le but des maps est de rendre le SCSS plus "pilotable" : on modifie les données au même endroit, puis tout le projet suit. C'est la base d'un design system maintenable et cohérent.

Erreurs courantes

Erreur 1 : maps trop complexes et illisibles

Les maps imbriquées sont puissantes, mais si tu fais des structures trop profondes (plus de 2-3 niveaux), ton SCSS devient difficile à comprendre et à déboguer.

À éviter

Les maps avec plusieurs niveaux d'imbrication qui nécessitent des fonctions complexes pour accéder aux valeurs. La simplicité prime sur la sophistication.

Erreur 2 : utiliser des valeurs "magiques" malgré les maps

Si tu utilises encore 768px à droite à gauche alors que tu as une map de breakpoints, tu perds l'intérêt de la centralisation. Sois cohérent et utilise toujours tes maps.

Erreur 3 : oublier de gérer les clés invalides

Sans map-has-key() (ou un fallback), une simple faute de frappe peut casser la compilation ou produire des styles incorrects.

SCSS (ERREUR)
$colors: (primary: #7aa7ff);

.button {
  // Oubli de vérifier si la clé existe
  background: map-get($colors, primay); // Faute de frappe : "primay" au lieu de "primary"
  // Erreur : retourne null, le style ne sera pas appliqué
}

Résumé du chapitre

Ce que vous avez appris
Les maps stockent des paires clé/valeur et peuvent être imbriquées pour créer des structures complexes.
map-get() récupère une valeur, map-has-key() vérifie si une clé existe.
Les maps remplacent souvent des conditions répétitives (@if/@else), rendant le code plus propre.
Couleurs, tailles, breakpoints et thèmes sont des usages courants et puissants des maps en production.
Les maps sont la base d'un design system SCSS cohérent et facile à maintenir.

Prochain chapitre : Héritage et @extend

Dans le prochain chapitre, nous verrons l'héritage en SCSS grâce à @extend. Nous découvrirons comment partager des styles entre sélecteurs, les avantages par rapport aux mixins, et surtout les pièges à éviter pour ne pas créer un CSS trop spécifique ou trop volumineux.

  • Comprendre le fonctionnement de @extend et sa syntaxe
  • Différence entre @extend et les mixins
  • Les placeholders (sélecteurs %) pour un héritage "propre"
  • Cas d'usage appropriés et pièges à éviter
  • Impact sur la spécificité CSS et les performances