IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

La fonctionnalité CSS Nesting Module passe en « First Public Working Draft »
La possibilité d'imbriquer des sélecteurs CSS se dirige vers une normalisation

Le , par Stéphane le calme

20PARTAGES

10  0 
Le 31 août, le CSS Nesting Module a été publié avec le statut « First Public Working Draft ». Il a ainsi définitivement quitté le statut de « Editor's Draft », qu'il détenait depuis mars 2019, et peut être considéré comme un consensus reconnu par le CSS Working Group (CSSWG). Cela ouvre la voie à la norme.

Les préprocesseurs connaissent les CSS imbriqués depuis les années 2000

La fonctionnalité, qui a été proposée pour la première fois en 2011 dans une liste de diffusion W3C par l'éditeur en charge, Tab Atkins, un développeur de Google, sous le nom de « Selector Nesting », apporte pour la première fois la possibilité d'imbriquer des sélecteurs CSS en natif, c'est-à-dire sans avoir besoin d'autres outils.

Les développeurs qui travaillent déjà avec des préprocesseurs tels que Sass, Less, SCSS ou, plus récemment, PostCSS utilisent l'imbrication de sélecteurs dans la syntaxe interne des outils de préprocesseur depuis 2007. Il est considéré comme l'un des principaux arguments en faveur de l'utilisation de Sass and Co. Pour une utilisation sur le Web, les préprocesseurs génèrent un CSS conforme à la norme. À l'avenir, les règles d'imbrication devraient appartenir à ce CSS conforme à la norme.

Le CSSWG décrit la fonctionnalité comme suit : « Ce module décrit la prise en charge de l'imbrication d'une règle de style dans une autre règle de style afin que le sélecteur de la règle interne puisse référencer les éléments de la règle externe. Avec cette fonction, les styles associés peuvent être résumés dans une structure unique au sein du document CSS, ce qui améliore la lisibilité grâce à une hiérarchie visuelle et la maintenabilité en évitant les répétitions. »

Motivation

Le CSS pour les pages Web, même modérément compliquées, comprend souvent de nombreuses duplications dans le but de styliser le contenu associé. Par exemple, voici une partie du balisage CSS pour une version du module [CSS-COLOR-3]*:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
table.colortable td {
  text-align:center;
}
table.colortable td.c {
  text-transform:uppercase;
}
table.colortable td:first-child, table.colortable td:first-child+td {
  border:1px solid black;
}
table.colortable th {
  text-align:center;
  background:black;
  color:white;
}

L'imbrication permet de regrouper des règles de style associées, comme ceci*:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
table.colortable {
  & td {
    text-align:center;
    &.c { text-transform:uppercase }
    &:first-child, &:first-child + td { border:1px solid black }
  }
  & th {
    text-align:center;
    background:black;
    color:white;
  }
}

Outre la suppression des doublons, le regroupement des règles associées améliore la lisibilité et la maintenabilité du CSS résultant.

Imbrication directe et indirecte

Les règles de style peuvent être imbriquées dans d'autres règles de style. Ces règles de style imbriquées agissent exactement comme des règles de style ordinaires (associant des propriétés à des éléments via des sélecteurs) mais elles « héritent » du contexte de sélecteur de leur règle parent, leur permettant de s'appuyer davantage sur le sélecteur du parent sans avoir à le répéter, éventuellement plusieurs fois.

Il existe deux syntaxes étroitement liées pour créer des règles de style imbriquées*:

  • Imbrication directe, où la règle de style imbriquée est écrite normalement à l'intérieur de la règle parent, mais avec l'exigence que le sélecteur de la règle de style imbriqué soit préfixé par imbrication.
  • La règle @nest, qui impose moins de contraintes sur le sélecteur de la règle de style imbriqué.

Mis à part la légère différence dans la façon dont elles sont écrites, les deux méthodes sont exactement équivalentes en termes de fonctionnalités.

Imbrication directe

Une règle de style peut être directement imbriquée dans une autre règle de style si son sélecteur est préfixé par imbrication.

Pour être préfixé par imbrication, un sélecteur d'imbrication doit être le premier sélecteur simple dans le premier sélecteur composé du sélecteur. Si le sélecteur est une liste de sélecteurs, chaque sélecteur complexe de la liste doit être préfixé par imbrication pour que le sélecteur dans son ensemble soit préfixé par imbrication.

Par exemple, les imbrications suivantes sont valides*:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* & can be used on its own */
.foo {
  color: blue;
  & > .bar { color: red; }
}
/* equivalent to
  .foo { color: blue; }
  .foo > .bar { color: red; }
*/
 
 
/* or in a compound selector,
   refining the parent’s selector */
.foo {
  color: blue;
  &.bar { color: red; }
}
/* equivalent to
  .foo { color: blue; }
  .foo.bar { color: red; }
*/
 
/* multiple selectors in the list must all
   start with & */
.foo, .bar {
  color: blue;
  & + .baz, &.qux { color: red; }
}
/* equivalent to
  .foo, .bar { color: blue; }
  :is(.foo, .bar) + .baz,
  :is(.foo, .bar).qux { color: red; }
*/
 
/* & can be used multiple times in a single selector */
.foo {
  color: blue;
  & .bar & .baz & .qux { color: red; }
}
/* equivalent to
  .foo { color: blue; }
  .foo .bar .foo .baz .foo .qux { color: red; }
*/
 
/* Somewhat silly, but can be used all on its own, as well. */
.foo {
  color: blue;
  & { padding: 2ch; }
}
/* equivalent to
  .foo { color: blue; }
  .foo { padding: 2ch; }
 
  // or
 
  .foo {
    color: blue;
    padding: 2ch;
  }
*/
 
/* Again, silly, but can even be doubled up. */
.foo {
  color: blue;
  && { padding: 2ch; }
}
/* equivalent to
  .foo { color: blue; }
  .foo.foo { padding: 2ch; }
*/
 
/* The parent selector can be arbitrarily complicated */
.error, #404 {
  &:hover > .baz { color: red; }
}
/* equivalent to
  :is(.error, #404):hover > .baz { color: red; }
*/
 
/* As can the nested selector */
.foo {
  &:is(.bar, &.baz) { color: red; }
}
/* equivalent to
  .foo:is(.bar, .foo.baz) { color: red; }
*/
 
/* Multiple levels of nesting "stack up" the selectors */
figure {
  margin: 0;
 
  & > figcaption {
    background: hsl(0 0% 0% / 50%);
 
    & > p {
      font-size: .9rem;
    }
  }
}
/* equivalent to
  figure { margin: 0; }
  figure > figcaption { background: hsl(0 0% 0% / 50%); }
  figure > figcaption > p { font-size: .9rem; }
*/

Mais ces imbrications ne sont pas valides :

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* No & at all */
.foo {
  color: blue;
  .bar {
    color: red;
  }
}
 
/* & isn’t the first simple selector */
.foo {
  color: blue;
  .bar& {
    color: red;
  }
}
 
/* & isn’t the first selector of every one in the list */
.foo, .bar {
  color: blue;
  & + .baz, .qux { color: red; }
}

Le dernier exemple ici n'est pas techniquement ambigu, car le sélecteur dans son ensemble commence par un &, mais c'est un risque d'édition - si la règle est remaniée pour supprimer le premier sélecteur ou réorganiser les sélecteurs dans la liste, ce qui normalement serait toujours valide, il en résulterait un sélecteur invalide désormais ambigu.

Certains outils de génération CSS concaténeront des sélecteurs tels que des chaînes, permettant aux auteurs de créer un seul sélecteur simple à travers les niveaux d'imbrication. Ceci est parfois utilisé par des méthodes d'organisation de sélecteurs comme BEM pour réduire la répétition dans un fichier, lorsque les sélecteurs eux-mêmes ont une répétition importante en interne.

Par exemple, si un composant utilise la classe .foo et qu'un composant imbriqué utilise .foo__bar, vous pouvez l'écrire dans Sass comme suit*:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
.foo {
  color: blue;
  &__bar { color: red; }
}
/* In Sass, this is equivalent to
   .foo { color: blue; }
   .foo__bar { color: red; }
*/

Malheureusement, cette méthode est incompatible avec la syntaxe du sélecteur en général et nécessite au mieux des heuristiques adaptées aux pratiques d'écriture de sélecteur pour reconnaître quand l'auteur le souhaite, ou quand l'auteur essaye d'ajouter un sélecteur de type dans la règle imbriquée. __bar, par exemple, est un nom d'élément personnalisé valide en HTML.

En tant que tel, CSS ne peut pas faire cela ; les composants de sélecteur imbriqués sont interprétés seuls et non "concaténés":

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
.foo {
  color: blue;
  &__bar { color: red; }
}
/* In CSS, this is instead equivalent to
   .foo { color: blue; }
   __bar.foo { color: red; }
*/

La règle d'imbrication*: @nest

Bien que l'imbrication directe ait l'air agréable, elle est quelque peu fragile. Certains sélecteurs d'imbrication valides, comme .foo &, ne sont pas autorisés, et la modification du sélecteur de certaines manières peut rendre la règle invalide de manière inattendue. De plus, certains auteurs trouvent que l'imbrication est difficile à distinguer visuellement des déclarations environnantes.

Pour aider à résoudre tous ces problèmes, cette spécification définit la règle @nest, qui impose moins de restrictions sur la manière d'imbriquer validement les règles de style. Sa syntaxe est : @nest = @nest <selector-list> { <style-block> }.

La règle @nest n'est valide qu'à l'intérieur d'une règle de style. Si elle est utilisée dans un autre contexte (en particulier, au niveau supérieur d'une feuille de style), la règle n'est pas valide.

La règle @nest fonctionne de la même manière qu'une règle de style imbriquée*: elle commence par un sélecteur et contient un bloc de déclarations qui s'appliquent aux éléments auxquels le sélecteur correspond. Ce bloc est traité de la même manière qu'un bloc de règle de style, donc tout ce qui est valide dans une règle de style (comme des règles @nest supplémentaires) est également valide ici.

La seule différence entre @nest et une règle de style directement imbriquée est que le sélecteur utilisé dans une règle @nest est moins contraint : il doit seulement être nest-containing, ce qui signifie qu'il contient un sélecteur d'imbrication quelque part, plutôt que de l'exiger être au début de chaque sélecteur. Une liste de sélecteurs contient des imbrications si tous ses sélecteurs complexes individuels contiennent des imbrications.

Tout ce que vous pouvez faire avec l'imbrication directe, vous pouvez le faire avec une règle @nest, donc ce qui suit est valide*:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
.foo {
  color: red;
  @nest & > .bar {
    color: blue;
  }
}
/* equivalent to
  .foo { color: red; }
  .foo > .bar { color: blue; }
*/

Mais @nest autorise les sélecteurs qui ne commencent pas par un &, les éléments suivants sont donc également valides*:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.foo {
  color: red;
  @nest .parent & {
    color: blue;
  }
}
/* equivalent to
  .foo { color: red; }
  .parent .foo { color: blue; }
*/
 
.foo {
  color: red;
  @nest :not(&) {
    color: blue;
  }
}
/* equivalent to
  .foo { color: red; }
  :not(.foo) { color: blue; }
*/

Mais les éléments suivants ne sont pas valides*:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.foo {
  color: red;
  @nest .bar {
    color: blue;
  }
}
/* Invalid because there’s no nesting selector */
 
.foo {
  color: red;
  @nest & .bar, .baz {
    color: blue;
  }
}
/* Invalid because not all selectors in the list
  contain a nesting selector */

Les règles de style directement imbriquées et les règles @nest peuvent être mélangées arbitrairement. Par exemple:

Code CSS : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
.foo {
  color: blue;
  @nest .bar & {
    color: red;
    &.baz {
      color: green;
    }
  }
}
/* equivalent to
  .foo { color: blue; }
  .bar .foo { color: red; }
  .bar .foo.baz { color: green; }

En somme

La spécification prévoit une imbrication directe et indirecte, la variante indirecte étant recommandée car soumise à moins de restrictions et est également plus facile à distinguer visuellement dans le code. L'imbrication directe doit être effectuée en plaçant une esperluette (&), le véritable sélecteur d'imbrication, devant le sélecteur à imbriquer. Les utilisateurs de préprocesseurs connaissent le & comme « Sélecteur parent » ou « Parent Combinator ».

Avec l'imbrication indirecte, la règle précédente est @nest suivi du sélecteur d'imbrication &. Fondamentalement, seul l'effort de frappe inférieur plaide en faveur de l'utilisation du & seul. Sinon @nest peut faire tout ce qui serait également possible avec &.

Le sélecteur d'imbrication & ne peut être utilisé valablement que là où il apparaît en première position. Cela est dû au processus d'analyse du navigateur. Il parcourt hiérarchiquement le code et ne peut pas faire la distinction entre les propriétés et les sélecteurs si les noms sont identiques. Si le sélecteur d'imbrication venait après lui, il serait tout simplement trop tard pour être utile à une différenciation.

Il est également possible de faire un mix d'imbrication directe et indirecte.

Source : W3C

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de Zefling
Expert confirmé https://www.developpez.com
Le 04/09/2021 à 23:37
Citation Envoyé par Se7h22 Voir le message
Je suis tout seul à trouver ça moche comme façon de coder ? Déjà que certains font du code bien dégueulasse en CSS, avec ça je crains le pire…

Après si ça peu sauver à des rares occasions, pourquoi pas. Mais bon… Après cela veut peut-être dire que je vieilli 😅
Heu... en gros c'est ce qu'on fait en LESS ou SASS depuis 10 ans. Je ne comprends pas cette remarque.
1  0 
Avatar de Daïmanu
Membre chevronné https://www.developpez.com
Le 02/09/2021 à 15:49
En définitive on reprend la structure hiérarchique des balises html, et on l'adapte pour le css.

Est-ce qu'on peut espérer une implémentation prochaine dans les navigateurs ?
0  0 
Avatar de Se7h22
Membre averti https://www.developpez.com
Le 04/09/2021 à 0:58
Je suis tout seul à trouver ça moche comme façon de coder ? Déjà que certains font du code bien dégueulasse en CSS, avec ça je crains le pire…

Après si ça peu sauver à des rares occasions, pourquoi pas. Mais bon… Après cela veut peut-être dire que je vieilli 😅
0  0 
Avatar de Se7h22
Membre averti https://www.developpez.com
Le 05/09/2021 à 10:57
Citation Envoyé par Zefling Voir le message
Heu... en gros c'est ce qu'on fait en LESS ou SASS depuis 10 ans. Je ne comprends pas cette remarque.
Sauf que ça reste des technologies qui ne sont pas majoritairement utilisés, ou qui demande une certaine rigueur pour les adopter. Ici c'est un changement directement sur la norme CSS, donc cela poussera même les plus amateurs du CSS à l'utiliser (et dans le monde pro il y a également beaucoup d'amateur CSS ).
0  0 
Avatar de Zefling
Expert confirmé https://www.developpez.com
Le 05/09/2021 à 14:15
Citation Envoyé par Se7h22 Voir le message
Sauf que ça reste des technologies qui ne sont pas majoritairement utilisés, ou qui demande une certaine rigueur pour les adopter. Ici c'est un changement directement sur la norme CSS, donc cela poussera même les plus amateurs du CSS à l'utiliser (et dans le monde pro il y a également beaucoup d'amateur CSS ).
Dans le monde pro, depuis plus de 6 ans, j'ai jamais eu un projet qui n'utilise pas SASS ou LESS. C'est un tel gain de temps que c'est dur de s'en passer.

Pour moi, il y a des modules CSS bien plus compliqué à apprendre comme Flex ou encore pire Grid. Sauf que ces modules commencent doucement à être utilisé vu les avantage certains qu'ils apportent.

De toute façon, beaucoup de chose qui se font en CSS viennent de demande du secteur pro. Toute ce qui se rapporte aux fontes, aux polices de caractères, à la colorimétrie, je suis pas sûr que ça serve au péquin moyen. Et ça sera pire avec layout() et paint() qui demande carrément de savoir vraiment coder.
0  0 
Avatar de Se7h22
Membre averti https://www.developpez.com
Le 05/09/2021 à 14:42
Citation Envoyé par Zefling Voir le message
Dans le monde pro, depuis plus de 6 ans, j'ai jamais eu un projet qui n'utilise pas SASS ou LESS. C'est un tel gain de temps que c'est dur de s'en passer.

Pour moi, il y a des modules CSS bien plus compliqué à apprendre comme Flex ou encore pire Grid. Sauf que ces modules commencent doucement à être utilisé vu les avantage certains qu'ils apportent.

De toute façon, beaucoup de chose qui se font en CSS viennent de demande du secteur pro. Toute ce qui se rapporte aux fontes, aux polices de caractères, à la colorimétrie, je suis pas sûr que ça serve au péquin moyen. Et ça sera pire avec layout() et paint() qui demande carrément de savoir vraiment coder.
Après, si c'est comme pour Grid qui permet de se passer des framework comme Bootstrap, c'est tant mieux. Moins on aura de framework mieux on se portera. Mais, visuellement, je suis clairement pas fan.
0  0