frontend / css
CSS moderne expert : nesting, @container, @scope, @property
Explication
Ce que vous allez apprendre
- Imbriquer des règles CSS nativement, sans préprocesseur comme Sass
- Typer une custom property avec
@propertypour la rendre animable - Limiter la portée d'un ensemble de règles avec
@scope, sans dépendre de la spécificité - Combiner nesting,
@containeretcolor-mix()dans un style de composant moderne
Dans quel contexte ?
Une équipe migre progressivement son projet Sass vers du CSS natif pour supprimer une étape de build devenue difficile à maintenir. Elle doit reproduire l'imbrication de règles (&:hover, & .titre) et l'animation fluide d'une barre de progression dont la couleur changeait dynamiquement — un cas qui, avec de simples variables CSS classiques, ne pouvait pas être animé en douceur. Cette leçon montre les outils natifs qui remplacent ces besoins.
Étape 1 : le CSS rattrape les préprocesseurs
Pendant des années, l'imbrication de règles ou le mélange de couleurs n'existaient qu'à travers des préprocesseurs comme Sass, qui transformaient ce code en CSS classique avant de l'envoyer au navigateur.
Étape 2 : ce que cette leçon présente
Voici les fonctionnalités les plus récentes qui rendent ces outils de moins en moins indispensables : le CSS natif sait désormais faire une grande partie de ce qui nécessitait une étape de compilation.
Étape 3 : le nesting natif, imbriquer sans compilateur
Commençons par le plus visible : écrire les styles d'un composant en imbriquant ses sous-éléments (.carte { & .titre { ... } &:hover { ... } }) rend le code plus lisible qu'une liste plate de sélecteurs répétés, sans étape de build.
Étape 4 : un piège peu connu des variables classiques
Passons à un problème plus subtil. Les variables CSS classiques ne peuvent pas être animées en douceur via transition, car le navigateur ne sait pas s'il s'agit d'un nombre, d'une couleur ou d'un texte.
Le saviez-vous ?
Une transition: --ma-variable 0.3s sur une custom property CSS classique ne produit AUCUNE animation visible : le navigateur bascule instantanément d'une valeur à l'autre. Seule une variable déclarée via @property avec un syntax précis devient réellement interpolable.
Étape 5 : la solution, @property
@property résout ce problème en déclarant explicitement le TYPE d'une variable, ce qui permet enfin au navigateur de l'animer progressivement, comme n'importe quelle propriété native.
Étape 6 : @scope, contenir les styles sans spécificité
Il reste un dernier outil utile : quand du contenu externe est injecté dans une page, ses styles peuvent accidentellement "fuiter". @scope limite explicitement où une règle CSS s'applique, en délimitant une zone de départ et de fin.
| Fonctionnalité | Remplace (côté Sass) | Avantage natif |
|---|---|---|
Nesting (&) | imbrication Sass | pas d'étape de compilation |
@property | — (inexistant en Sass) | rend une variable animable |
@scope | conventions de nommage manuelles | portée garantie par le navigateur |
color-mix() | fonctions mix()/lighten() | calcul de couleur natif, sans build |
Et ensuite ?
C'est une solution plus structurelle que de jongler avec la spécificité. Une fois ces outils modernes compris, la prochaine étape montre comment le scroll lui-même peut piloter une animation.
Commandes & code
CSS moderne expert
Les dernières fonctionnalités qui rapprochent le CSS natif des préprocesseurs, en mieux intégré au navigateur.
/* Nesting natif : plus besoin de Sass pour imbriquer des règles */
.carte {
padding: 16px;
border: 1px solid #e5e5e5;
& .titre {
font-size: 1.25rem;
font-weight: 600;
}
& .description {
color: #666;
}
&:hover {
border-color: var(--couleur-primaire);
}
&.mise-en-avant {
border-width: 2px;
}
@media (min-width: 640px) {
padding: 24px;
}
}/* @scope : limite la portée d'un ensemble de règles à un sous-arbre précis,
sans dépendre de la spécificité pour éviter les fuites de style */
@scope (.article) to (.commentaires) {
p {
line-height: 1.7;
}
img {
max-width: 100%;
}
}/* @property : type fort pour les custom properties -> permet de les ANIMER,
ce que les variables CSS classiques ne permettaient pas nativement */
@property --progression {
syntax: "<percentage>";
inherits: false;
initial-value: 0%;
}
.barre-progression {
background: conic-gradient(var(--couleur-primaire) var(--progression), #e5e5e5 0);
transition: --progression 0.6s ease;
}
.barre-progression.complete {
--progression: 100%;
}/* @container avec nesting : composition experte */
.widget {
container-type: inline-size;
& .contenu {
display: grid;
gap: 8px;
}
@container (min-width: 480px) {
& .contenu {
grid-template-columns: 1fr 1fr;
}
}
}
/* color-mix() : mélange deux couleurs directement en CSS, sans préprocesseur */
.bouton-survol {
background: color-mix(in srgb, var(--couleur-primaire) 85%, black);
}
/* :has() + nesting + variables : un exemple représentatif du CSS "expert" 2026 */
.formulaire {
--couleur-validation: #16a34a;
&:has(input:invalid) {
--couleur-validation: #dc2626;
}
& .indicateur {
background: var(--couleur-validation);
transition: background 0.2s;
}
}Résumé
- Le nesting natif couvre l'essentiel des cas d'usage Sass, sans étape de compilation.
@scopeborne explicitement la portée d'un style, utile face à du contenu tiers/injecté.@propertytype une custom property et la rend enfin animable viatransition.color-mix()calcule des variations de couleur directement en CSS, sans fonctions de préprocesseur.
Exercices pratiques
Mission : une barre de progression qui saute au lieu de glisser
Objectif : Diagnostiquer pourquoi une custom property classique ne s'anime pas, et migrer un fragment Sass vers du nesting natif.
Contexte
Sur progression.css, une barre utilise background: conic-gradient(var(--couleur-primaire) var(--progression), #e5e5e5 0); avec transition: --progression 0.6s ease;, mais --progression est une simple custom property déclarée uniquement via :root { --progression: 0%; }, sans aucun @property. Résultat : au clic sur "Suivant", la barre saute instantanément de 0% à 40% au lieu de glisser progressivement. Par ailleurs, l'équipe veut migrer une règle Sass .carte { &:hover { border-color: blue; } & .titre { font-weight: 600; } } vers du CSS nesting natif.