📚 Cours SCSS (Sass) 📍 Chapitre 5 / 21

Imbrication des règles (Nesting)

Le nesting (imbrication) est l'une des fonctionnalités les plus appréciées de SCSS : elle permet d'écrire des styles d'une manière plus proche de la structure HTML. Mais attention : mal utilisé, le nesting peut créer un CSS trop spécifique et difficile à maintenir. Ici, nous apprenons à l'utiliser proprement, avec des exemples concrets et des règles claires.

Objectifs du chapitre

  • Comprendre le principe de l'imbrication en SCSS et son utilité.
  • Savoir imbriquer des sélecteurs sans créer de CSS "fragile".
  • Maîtriser le symbole & (sélecteur parent) pour les états et variantes.
  • Identifier les limites du nesting et appliquer les bonnes pratiques.
  • Distinguer les cas où le nesting est bénéfique de ceux où il est néfaste.
À retenir

Le nesting sert principalement à améliorer la lisibilité et l'organisation du code SCSS. S'il rend le CSS final plus compliqué ou trop spécifique, c'est que tu vas trop loin.

Explications théoriques détaillées

Pourquoi le nesting existe-t-il ?

En CSS classique, tu écris souvent des sélecteurs répétitifs pour cibler des éléments à l'intérieur d'un parent spécifique :

CSS
.card { 
  padding: 16px; 
  border-radius: 12px;
}

.card h2 { 
  margin: 0 0 8px;
  font-size: 18px;
}

.card a { 
  color: #7aa7ff; 
}

.card a:hover { 
  text-decoration: underline; 
}

SCSS permet d'écrire tout cela dans un bloc unique .card pour regrouper la logique et améliorer la lisibilité :

SCSS
.card {
  padding: 16px;
  border-radius: 12px;

  h2 {
    margin: 0 0 8px;
    font-size: 18px;
  }

  a {
    color: #7aa7ff;

    &:hover {
      text-decoration: underline;
    }
  }
}

Le compilateur SCSS générera automatiquement le CSS standard avec les sélecteurs complets, comme dans le premier exemple.

Comprendre le symbole & (sélecteur parent)

Le caractère & représente le sélecteur "parent" courant. Il est essentiel pour écrire des variantes, des pseudo-classes, des pseudo-éléments et des états sans répéter le sélecteur de base.

SCSS
.btn {
  padding: 12px 24px;
  border-radius: 8px;
  background: #7aa7ff;
  color: white;
  border: none;
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    background: #5a8fff;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(122, 167, 255, 0.3);
  }

  &:focus {
    outline: 2px solid #7aa7ff;
    outline-offset: 2px;
  }

  &:active {
    transform: translateY(0);
  }
}

CSS généré :

CSS
.btn {
  padding: 12px 24px;
  border-radius: 8px;
  background: #7aa7ff;
  color: white;
  border: none;
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn:hover {
  background: #5a8fff;
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(122, 167, 255, 0.3);
}

.btn:focus {
  outline: 2px solid #7aa7ff;
  outline-offset: 2px;
}

.btn:active {
  transform: translateY(0);
}
À retenir

& signifie "le sélecteur actuel". C'est particulièrement utile pour :hover, :focus, :active, :disabled, .is-active, .is-loading, etc. Cela permet de garder tous les états d'un composant regroupés au même endroit.

Le risque principal : la sur-spécificité

Plus tu imbriques profondément, plus les sélecteurs générés deviennent longs et spécifiques. Cela crée plusieurs problèmes :

  • Difficulté de réutilisation : les styles sont liés à une structure HTML précise
  • Problèmes de surcharge : il faut des sélecteurs encore plus spécifiques pour modifier les styles
  • Performance : les sélecteurs longs sont plus lents à évaluer (bien que l'impact soit généralement faible)
  • Maintenabilité : difficile de comprendre et modifier le code plus tard
Conseil terrain

Dans la majorité des projets, un nesting de 1 à 2 niveaux suffit. Si tu dépasses souvent 3 niveaux, c'est un signal d'alerte que ton code pourrait être mieux structuré avec des classes dédiées.

Exemples simples

Imbrication simple : titres et liens dans une carte

Un cas d'usage classique : styliser les éléments enfants d'un composant.

SCSS :

SCSS
.card {
  padding: 16px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);

  h2 {
    margin: 0 0 8px;
    font-size: 18px;
    color: #ffffff;
    font-weight: 700;
  }

  p {
    margin: 0 0 12px;
    color: rgba(255, 255, 255, 0.8);
    line-height: 1.6;
  }

  a {
    color: #7aa7ff;
    text-decoration: none;
    font-weight: 500;

    &:hover {
      text-decoration: underline;
      color: #5a8fff;
    }
  }
}

CSS généré :

CSS
.card {
  padding: 16px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.card h2 {
  margin: 0 0 8px;
  font-size: 18px;
  color: #ffffff;
  font-weight: 700;
}

.card p {
  margin: 0 0 12px;
  color: rgba(255, 255, 255, 0.8);
  line-height: 1.6;
}

.card a {
  color: #7aa7ff;
  text-decoration: none;
  font-weight: 500;
}

.card a:hover {
  text-decoration: underline;
  color: #5a8fff;
}

Variantes d'un composant avec & (pattern BEM)

Un pattern fréquent en développement front-end : une classe de base avec des variantes modifiées. SCSS facilite grandement ce type d'architecture.

SCSS
.btn {
  padding: 10px 16px;
  border-radius: 12px;
  background: #7aa7ff;
  color: white;
  border: none;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.2s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;

  &:hover {
    background: #5a8fff;
    transform: translateY(-2px);
  }

  &--secondary {
    background: transparent;
    border: 1px solid #7aa7ff;
    color: #7aa7ff;

    &:hover {
      background: rgba(122, 167, 255, 0.1);
      transform: translateY(-2px);
    }
  }

  &--danger {
    background: #ef4444;

    &:hover {
      background: #dc2626;
    }
  }

  &--large {
    padding: 14px 20px;
    font-size: 18px;
  }

  &--small {
    padding: 6px 12px;
    font-size: 14px;
  }

  &[disabled] {
    opacity: 0.5;
    cursor: not-allowed;

    &:hover {
      transform: none;
    }
  }
}

CSS généré (extrait) :

CSS
.btn {
  padding: 10px 16px;
  border-radius: 12px;
  background: #7aa7ff;
  color: white;
  border: none;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.2s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.btn:hover {
  background: #5a8fff;
  transform: translateY(-2px);
}

.btn--secondary {
  background: transparent;
  border: 1px solid #7aa7ff;
  color: #7aa7ff;
}

.btn--secondary:hover {
  background: rgba(122, 167, 255, 0.1);
  transform: translateY(-2px);
}

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

.btn--danger:hover {
  background: #dc2626;
}

.btn--large {
  padding: 14px 20px;
  font-size: 18px;
}

.btn--small {
  padding: 6px 12px;
  font-size: 14px;
}

.btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn[disabled]:hover {
  transform: none;
}
À retenir

Ce style de variantes ressemble à la méthodologie BEM (.btn--secondary). SCSS facilite énormément l'écriture et la maintenance de ces patterns. Tous les états et variantes sont regroupés dans le même bloc, ce qui rend le composant plus compréhensible et cohérent.

Exemples concrets et professionnels

Composant "navigation" : nesting propre et maintenable

Un exemple classique : un menu de navigation avec des liens et un état "actif". Nous voulons un nesting lisible, mais pas trop profond pour maintenir la flexibilité.

SCSS
.nav {
  display: flex;
  gap: 12px;
  list-style: none;
  padding: 0;
  margin: 0;

  .nav__item {
    position: relative;

    .nav__link {
      color: rgba(255, 255, 255, 0.85);
      text-decoration: none;
      padding: 8px 12px;
      border-radius: 6px;
      transition: all 0.2s ease;
      display: block;

      &:hover {
        color: #7aa7ff;
        background: rgba(122, 167, 255, 0.1);
      }

      &.is-active {
        color: #7aa7ff;
        font-weight: 700;
        background: rgba(122, 167, 255, 0.15);

        &::after {
          content: '';
          position: absolute;
          bottom: -4px;
          left: 12px;
          right: 12px;
          height: 2px;
          background: #7aa7ff;
          border-radius: 1px;
        }
      }
    }
  }

  // Variante verticale
  &--vertical {
    flex-direction: column;
    gap: 4px;

    .nav__item {
      .nav__link {
        padding: 10px 16px;
      }
    }
  }
}

Pourquoi c'est "propre" ?

  • On reste à 2-3 niveaux maximum (raisonnable pour ce type de composant).
  • Les classes (.nav__link) restent réutilisables et compréhensibles.
  • L'état actif est explicite (.is-active) et regroupe ses styles.
  • La variante verticale est définie dans le même bloc avec &--vertical.
  • Les pseudo-éléments (::after) sont imbriqués là où ils ont du sens.

Quand éviter le nesting et préférer des classes indépendantes

Si tu écris quelque chose comme ci-dessous, tu risques de lier ton CSS à une structure HTML trop précise. Au moindre changement de structure, tu casses des styles et tu deviens dépendant d'une hiérarchie spécifique.

SCSS
/* EXEMPLE À ÉVITER : nesting trop dépendant du HTML */
.page {
  .layout {
    .content {
      .card {
        .title {
          font-size: 20px;
          color: #333;

          .icon {
            margin-right: 8px;
          }
        }

        .description {
          .highlight {
            background: yellow;
          }
        }
      }
    }
  }
}

Le CSS généré serait extrêmement spécifique et difficile à réutiliser : .page .layout .content .card .title .icon

Une meilleure approche est souvent de donner des classes claires et de les styliser directement :

SCSS
/* MEILLEURE APPROCHE : classes indépendantes */
.card__title {
  font-size: 20px;
  color: #333;
}

.card__icon {
  margin-right: 8px;
}

.card__description {
  line-height: 1.6;
}

.highlight {
  background: rgba(255, 255, 0, 0.3);
  padding: 0 2px;
  border-radius: 2px;
}
Conseil terrain

Plus ton CSS est dépendant de la structure HTML, plus ton code devient fragile. Préfère des classes sémantiques et réutilisables. Une bonne règle : si ton nesting génère des sélecteurs de plus de 3 parties (ex: .page .layout .content .card), c'est probablement trop spécifique.

Bonnes pratiques

Règles d'or pour un nesting efficace

  • Limiter la profondeur à 1-2 niveaux la plupart du temps, 3 niveaux maximum pour des cas spécifiques.
  • Utiliser & pour les états : :hover, :focus, .is-active, variantes BEM (&--modifier).
  • Privilégier les classes plutôt que dépendre de la hiérarchie HTML (éviter .parent .child .grandchild).
  • Éviter d'imbriquer des IDs ou des sélecteurs très spécifiques qui créent une haute spécificité.
  • Regrouper logiquement : imbriquer seulement les styles qui ont une relation directe avec le parent.
  • Penser réutilisation : si un style pourrait être utile ailleurs, le sortir du nesting.
  • Vérifier le CSS généré : regarder régulièrement le CSS produit pour s'assurer qu'il reste lisible et efficace.
À retenir

Le nesting est avant tout un outil de lisibilité et d'organisation du code SCSS, pas une façon de "cacher" des sélecteurs CSS complexes. Un bon nesting devrait rendre ton code SCSS plus clair sans rendre le CSS généré plus compliqué.

Erreurs courantes

Erreur 1 : nesting trop profond

Tu obtiens des sélecteurs longs comme .page .main .content .article .card .title qui sont difficiles à surcharger, à réutiliser et à comprendre. Souvent, c'est un signe qu'il manque des classes dédiées ou que l'architecture CSS pourrait être améliorée.

Erreur 2 : utiliser le nesting pour compenser une mauvaise structure CSS

Si tu dois imbriquer beaucoup pour "cibler correctement" un élément, c'est souvent que ton HTML/CSS manque de conventions claires (classes de composants, naming cohérent, architecture pensée). Le nesting ne devrait pas être une béquille pour une mauvaise organisation.

Erreur 3 : confondre nesting et performance

Le nesting SCSS ne rend pas ton site "plus rapide". Il rend ton code source plus lisible (si bien utilisé), mais le CSS final reste du CSS classique. En fait, un nesting excessif peut même générer du CSS moins performant à cause de sélecteurs trop spécifiques.

Erreur 4 : imbriquer des médias queries de manière désorganisée

SCSS permet d'imbriquer les médias queries à l'intérieur des sélecteurs, mais cela peut rendre difficile de voir tous les breakpoints au même endroit. Nous verrons les bonnes pratiques pour le responsive design dans un chapitre dédié.

Résumé du chapitre

Ce que vous avez appris
Le nesting regroupe les styles et améliore considérablement la lisibilité du code SCSS.
Le symbole & est essentiel pour les états, variantes et pseudo-classes.
Il faut éviter la sur-spécificité en limitant le nesting à 1-3 niveaux maximum.
Privilégier des classes réutilisables plutôt que dépendre de la hiérarchie HTML.
Le nesting est un outil d'organisation, pas une solution magique pour tous les problèmes CSS.

Prochain chapitre : Partials et organisation des fichiers SCSS

Maintenant que nous maîtrisons les variables et le nesting, il est temps d'apprendre à organiser un projet SCSS de manière professionnelle. Dans le prochain chapitre, nous découvrirons les partials et les meilleures pratiques pour structurer tes fichiers SCSS de façon scalable et maintenable.

  • Comprendre le concept de partials (fichiers partiels)
  • Organiser un projet SCSS avec une architecture claire
  • Utiliser @import vs @use (approche moderne)
  • Créer une structure de fichiers scalable pour les grands projets
  • Bonnes pratiques de nommage et d'organisation