BaliseTonSite

Sélecteurs avancés

Utilise & et combine efficacement tes sélecteurs.

Imagine : tu es un archer magique avec différents types de flèches enchantées. Tu as des flèches de base, mais aussi des flèches qui changent de trajectoire selon la cible, qui se multiplient, ou qui héritent des propriétés d'autres flèches. Le sélecteur parent & en SCSS, c'est ta flèche la plus polyvalente : elle peut viser précisément n'importe quelle cible en s'adaptant au contexte.

9.1Le sélecteur parent & : rappel et approfondissement

On a déjà vu le & dans l'article sur le nesting, mais il cache bien plus de possibilités. Il représente le sélecteur parent et peut se placer n'importe où :

.bouton {
  background: #3498db;
  
  // États classiques
  &:hover { background: #2980b9; }
  &:active { transform: scale(0.98); }
  
  // Modificateurs
  &--large { font-size: 1.2rem; }
  &--small { font-size: 0.8rem; }
  
  // Contexte (parent modifie enfant)
  .theme-sombre & { border: 1px solid #555; }
}

9.2Placer & au milieu ou à la fin

Le & ne doit pas forcément être au début. Tu peux l'utiliser pour créer des sélecteurs complexes :

.produit {
  color: #333;
  
  // Le & à la fin = quand .produit est dans .promotion
  .promotion & {
    color: #e74c3c;
    font-weight: bold;
  }
  
  // Le & au milieu = entre deux classes
  .sidebar &.featured {
    border-left: 4px solid gold;
  }
  
  // Répéter le & pour la spécificité
  && {
    // Double classe .produit.produit (spécificité plus forte)
    color: #2c3e50 !important;
  }
}

Ça génère ce CSS :

.produit { color: #333; }

.promotion .produit {
  color: #e74c3c;
  font-weight: bold;
}

.sidebar .produit.featured {
  border-left: 4px solid gold;
}

.produit.produit {
  color: #2c3e50 !important;
}

9.3Sélecteurs d'attributs avancés

Combine le nesting avec les sélecteurs d'attributs pour cibler précisément :

.champ {
  padding: 0.5rem;
  border: 1px solid #ddd;
  
  // Différents types d'input
  &[type="email"] { 
    background-image: url("icone-email.svg");
  }
  
  &[type="password"] { 
    background-image: url("icone-lock.svg");
  }
  
  // Attribut commence par...
  &[class^="btn-"] {
    cursor: pointer;
    border-radius: 4px;
  }
  
  // Attribut contient...
  &[class*="danger"] {
    border-color: #e74c3c;
  }
  
  // Attribut finit par...
  &[src$=".svg"] {
    filter: brightness(0.8);
  }
}

9.4Pseudo-sélecteurs complexes

Exploite toute la puissance des pseudo-sélecteurs avec le nesting :

.liste-produits {
  
  .produit {
    padding: 1rem;
    border-bottom: 1px solid #eee;
    
    // Premier et dernier
    &:first-child { border-top: 1px solid #eee; }
    &:last-child { border-bottom: none; }
    
    // Alternance couleurs (zebré)
    &:nth-child(even) { background: #f9f9f9; }
    &:nth-child(odd) { background: white; }
    
    // Cibler des groupes spécifiques
    &:nth-child(3n+1) { 
      // Chaque 3ème élément en partant du 1er (1, 4, 7, 10...)
      font-weight: bold;
    }
    
    // Pseudo-sélecteurs négatifs
    &:not(.en-rupture) {
      cursor: pointer;
      
      &:hover { transform: translateY(-2px); }
    }
  }
}

9.5Combinateurs et relations

Maîtrise les relations entre éléments avec les combinateurs :

.carte {
  
  .titre {
    font-size: 1.5rem;
    
    // Élément directement suivant (frère adjacent)
    & + .sous-titre {
      margin-top: 0.5rem;
      color: #666;
    }
    
    // Tous les éléments suivants (frères généraux)
    & ~ .meta {
      font-size: 0.9rem;
      opacity: 0.7;
    }
  }
  
  // Enfant direct uniquement (pas petit-enfant)
  & > .contenu {
    padding: 1rem;
    
    // Mais les petits-enfants peuvent avoir d'autres styles
    .paragraphe {
      line-height: 1.6;
    }
  }
  
  // Descendant à n'importe quel niveau
  .bouton {
    background: #3498db;
  }
}

9.6Interpolation dans les sélecteurs

Combine l'interpolation vue dans l'article 2 avec les sélecteurs avancés pour créer des systèmes dynamiques :

// Générer des variantes de couleur
$couleurs: (
  primaire: #3498db,
  succes: #27ae60,
  danger: #e74c3c
);

@each $nom, $couleur in $couleurs {
  .btn-#{$nom} {
    background: $couleur;
    
    // États avec interpolation
    &:hover { background: darken($couleur, 10%); }
    &:active { background: darken($couleur, 15%); }
    
    // Variantes avec interpolation
    &.btn-#{$nom}--outline {
      background: transparent;
      border: 2px solid $couleur;
      color: $couleur;
    }
  }
}

// Sélecteurs conditionnels
$prefixe: "app";

.#{$prefixe}-container {
  max-width: 1200px;
  
  .#{$prefixe}-header & {
    background: #f8f9fa;
  }
}

9.7Sélecteurs en cascade et spécificité

Attention à la spécificité ! Plus tu imbriques, plus tes sélecteurs deviennent spécifiques :

// ⚠️ Attention à la spécificité excessive
.page {
  .section {
    .carte {
      .titre {
        // Sélecteur très spécifique : .page .section .carte .titre
        color: #333;
        
        .sidebar & {
          // Encore plus spécifique : .sidebar .page .section .carte .titre
          color: #666;
        }
      }
    }
  }
}

// ✅ Mieux : sélecteurs plus simples
.carte-titre {
  color: #333;
  
  .sidebar & { color: #666; }
}

// ✅ Ou utiliser des modificateurs
.carte {
  
  &__titre {
    color: #333;
    
    .sidebar & { color: #666; }
  }
}

Règle de spécificité

Plus tu imbriques profondément, plus il devient difficile de surcharger tes styles plus tard. Préfère des sélecteurs simples et utilise les classes modificatrices plutôt que l'imbrication excessive.

9.8Patterns avancés avec &

Quelques techniques avancées que tu peux utiliser dans tes projets :

// 1. État global qui affecte tout le composant
.modal {
  opacity: 0;
  transform: scale(0.8);
  transition: all 0.3s ease;
  
  &.is-open {
    opacity: 1;
    transform: scale(1);
    
    // Quand modal ouverte, changer les enfants
    .overlay { background: rgba(0,0,0,0.5); }
    .contenu { animation: slideIn 0.3s ease; }
  }
}

// 2. Contexte responsive
.composant {
  font-size: 1rem;
  
  @media (max-width: 768px) {
    font-size: 0.9rem;
    
    // Dans ce contexte responsive...
    &.version-mobile {
      font-size: 0.8rem;
      
      .titre { font-size: 1.1rem; }
    }
  }
}

// 3. Sélecteur parent multiple
.theme-sombre,
.mode-contraste-eleve {
  
  .carte {
    background: #333;
    color: white;
    
    &:hover { background: #444; }
  }
}

9.9Debugging des sélecteurs complexes

Quand tes sélecteurs deviennent complexes, voici comment t'y retrouver :

// Utilise @debug pour voir le sélecteur généré
.composant {
  @debug &; // Affiche : .composant
  
  &--modifier {
    @debug &; // Affiche : .composant--modifier
    
    .parent & {
      @debug &; // Affiche : .parent .composant--modifier
    }
  }
}

// Utilise des commentaires pour documenter
.navigation {
  
  // État : menu ouvert
  &.is-open {
    
    // Contexte : sur mobile uniquement
    @media (max-width: 768px) {
      
      // Élément : liens de navigation
      .nav-link {
        // Action : affichage en bloc
        display: block;
      }
    }
  }
}

Conseil de lisibilité

Si tu dois relire ton sélecteur deux fois pour comprendre ce qu'il cible, c'est qu'il est trop complexe. Divise-le en plusieurs règles plus simples ou utilise des classes explicites.

Verifie tes acquis

3 questions pour valider ce chapitre

1. Que produit .card { &__title {} } en CSS compile ?

Valide et sauvegarde ce chapitre

Ne perds pas le fil de ton apprentissage. Chaque QCM complété s'enregistre comme un checkpoint dans ton tableau de bord personnel. Crée ton profil de développeur gratuitement pour débloquer toutes les évaluations du site et suivre ta progression étape par étape.

Commencer l'aventure
Déjà membre ?Connecte-toi