Sélecteurs avancés
Utilise & et combine efficacement tes sélecteurs.
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; }
}
}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;
}
}
}
}