Maison >interface Web >tutoriel CSS >Apprivoiser la cascade avec des sélecteurs CSS BEM et modernes

Apprivoiser la cascade avec des sélecteurs CSS BEM et modernes

Jennifer Aniston
Jennifer Anistonoriginal
2025-03-10 11:59:17346parcourir

Taming the Cascade With BEM and Modern CSS Selectors

bem. Comme presque toutes les technologies de développement frontal, l'écriture de CSS au format BEM peut provoquer une polarisation. Mais dans mon cercle social Twitter, c'est au moins l'une des méthodes CSS les plus populaires.

Je pense personnellement que BEM est bon et je pense que vous devriez l'utiliser. Mais je peux aussi comprendre pourquoi vous pourriez ne pas l'utiliser.

Quelle que soit votre opinion de BEM, elle offre certains avantages, le plus grand avantage est qu'il aide à éviter des conflits spécifiques dans la cascade CSS. En effet, s'il est utilisé correctement, tout sélecteur écrit au format BEM doit avoir le même score de spécificité (0,1,0). Au fil des ans, j'ai conçu CSS pour de nombreux grands sites Web (pensez au gouvernement, aux universités et aux banques) et ce sont ces grands projets qui m'ont fait découvrir où Bem brille vraiment. L'écriture CSS est plus amusante lorsque vous êtes sûr que le style que vous écrivez ou l'édition n'affecte pas d'autres parties du site Web.

En fait, dans certains cas, l'ajout de spécificité est considéré comme complètement acceptable. Par exemple: :hover et :focus pseudo-classes. Leurs scores de spécificité sont de 0,2,0. L'autre est les pseudo-éléments - par exemple, ::before et ::after - leurs scores de spécificité sont 0,1,1. Cependant, dans le reste de cet article, supposons que nous ne nous attendons pas à une autre propagation spécifique. ?

mais je ne veux pas vraiment vous vendre bem. Au lieu de cela, je veux parler de la façon dont nous l'utilisons en conjonction avec des sélecteurs CSS modernes (par exemple :is(), :has(), :where(), etc.) pour un contrôle en cascade plus fort.

Qu'est-ce qu'un sélecteur CSS moderne?

La spécification CSS Selector Level 4 nous fournit des façons puissantes et relativement nouvelles de sélectionner des éléments. Certains de mes favoris incluent :is(), :where() et :not(), qui sont tous pris en charge par tous les navigateurs modernes et sont désormais sûrs à utiliser dans presque tous les projets.

:is() et :where() sont fondamentalement les mêmes, sauf qu'ils ont des effets différents sur la spécificité. Plus précisément, le score de spécificité de :where() est toujours 0,0,0. Oui, même :where(button#widget.some-class) n'est pas spécifique. Dans le même temps, la spécificité de :is() est la spécificité de l'élément le plus spécifique dans sa liste de paramètres. Par conséquent, nous avons déjà la différence de finition en cascade entre deux sélecteurs modernes qui peuvent être utilisés.

Le puissant :has() pseudo-classe relationnelle gagne également rapidement le soutien du navigateur (à mon avis, c'est la plus grande fonctionnalité de CSS depuis Grid). Cependant, au moment de la rédaction, le support du navigateur pour :has() n'est pas assez bon pour être utilisé dans des environnements de production.

Permettez-moi d'ajouter une pseudo-classe à mon bem ...

<code>/* ❌ 特异性分数:0,2,0 */
.something:not(.something--special) {
  /* 所有 something 的样式,除了特殊的 something */
}</code>

Oh non! Avez-vous vu ce score spécifique? N'oubliez pas qu'avec BEM, nous nous attendons idéalement à ce que nos sélecteurs aient des scores spécifiques de 0,1,0. Pourquoi 0,2,0 n'est pas bon? Considérez un exemple d'extension similaire:

<code>.something:not(a) {
  color: red;
}
.something--special {
  color: blue;
}</code>

Même si le deuxième sélecteur apparaît enfin dans la séquence de code source, la spécificité supérieure du premier sélecteur (0,1,1) gagnera et la couleur de l'élément .something--special sera définie sur rouge. Autrement dit, supposons que votre BEM est écrit correctement et que l'élément sélectionné applique à la fois la classe de base .something et la classe de modificateur .something--special dans HTML.

S'ils sont utilisés mal, ces pseudo-classes peuvent affecter la cascade de manière inattendue. Ce sont ces incohérences qui peuvent causer des problèmes plus tard, en particulier dans les bases de code plus grandes et plus complexes.

Oh. Alors que faire maintenant?

Rappelez-vous ce que je viens de dire :where() et sa spécificité est nulle? Nous pouvons en profiter:

<code>/* ✅ 特异性分数:0,1,0 */
.something:where(:not(.something--special)) {
  /* 等 */
}</code>

La première partie de ce sélecteur (.something) obtient son score de spécificité habituel 0,1,0. Mais la spécificité de :where() - et tout ce qui s'y trouve est 0, et n'augmente pas davantage la spécificité du sélecteur.

: où () nous permet de nicher

Ceux qui ne se soucient pas autant de la spécificité que moi (et pour être juste, probablement beaucoup de gens) ont bien fait dans la nidification. Avec un typage de clavier aléatoire, nous pourrions obtenir des CS comme celui-ci (notez que j'utilise Sass pour la simplicité):

<code>.card { ... }

.card--featured {
  /* 等 */  
  .card__title { ... }
  .card__title { ... }
}

.card__title { ... }
.card__img { ... }</code>

Dans cet exemple, nous avons un composant .card. Lorsqu'il s'agit d'une carte "en vedette" (en utilisant la classe .card--featured), le titre et l'image de la carte doivent être des styles différents. Cependant, comme nous le savons maintenant, les scores de spécificité causés par le code ci-dessus sont incompatibles avec le reste de notre système. Un fanatique spécifique obstiné pourrait le faire:

ce n'est pas mal, non? Franchement, c'est un joli CSS.
<code>.card { ... }
.card--featured { ... }
.card__title { ... }
.card__title--featured { ... }
.card__img { ... }
.card__img--featured { ... }</code>

Cependant, HTML a également ses inconvénients. Les auteurs BEM expérimentés peuvent être douloureusement conscients que la logique de modèle complexe est nécessaire pour appliquer conditionnellement les classes de modificateurs à plusieurs éléments. Dans cet exemple, le modèle HTML doit ajouter conditionnellement la classe de modificateur

à trois éléments (

, --featured et .card), mais il peut être plus dans des exemples du monde réel. Il y a beaucoup de déclarations si. .card__title .card__img

Les sélecteurs peuvent nous aider à écrire moins de logique de modèle - et moins de classes BEM - sans augmenter le niveau de spécificité.

:where()

Ce qui suit est le même contenu dans SASS (Remarquez le fuite contre):
<code>.card { ... }
.card--featured { ... }

.card__title { ... }
:where(.card--featured) .card__title { ... }

.card__img { ... }
:where(.card--featured) .card__img { ... }</code>

si vous devez choisir cette méthode au lieu d'appliquer la classe de modificateur à divers éléments enfants dépend de la préférence personnelle. Mais au moins
<code>.card { ... }
.card--featured { ... }
.card__title { 
  /* 等 */ 
  :where(.card--featured) & { ... }
}
.card__img { 
  /* 等 */ 
  :where(.card--featured) & { ... }
}</code>
maintenant, nous avons le choix!

Que dois-je faire si je n'ai pas de BEM HTML?

Nous vivons dans un monde imparfait. Parfois, vous devez faire face à HTML qui dépasse votre contrôle. Par exemple, injectez un script tiers dont vous avez besoin pour styliser HTML. Ces balises ne sont généralement pas écrites à l'aide de noms de classe BEM, et dans certains cas, ces styles n'utilisent pas du tout des classes, mais des identifiants!

De même, :where() peut également nous aider à résoudre ce problème. Cette solution est un peu maladroite car nous devons nous référer à une classe dans l'arbre Dom que nous savons existe.

<code>/* ❌ 特异性分数:0,2,0 */
.something:not(.something--special) {
  /* 所有 something 的样式,除了特殊的 something */
}</code>

Citez l'élément parent se sent un peu risqué et restrictif. Et si la classe parent change ou n'existe pas pour une raison quelconque? Une meilleure solution (mais peut-être tout aussi maladroite) consiste à utiliser :is() à la place. N'oubliez pas que la spécificité de :is() est égale au sélecteur le plus spécifique de sa liste de sélecteurs.

afin que nous puissions utiliser :is() pour désigner une classe que nous connaissons (ou espérons!) Existe, plutôt que d'utiliser :where() comme dans l'exemple ci-dessus.

<code>.something:not(a) {
  color: red;
}
.something--special {
  color: blue;
}</code>

L'élément toujours existant body nous aidera à sélectionner l'élément #widget, et la présence de la classe :is() dans la même .dummy-class fera que le sélecteur body aura le même score de spécificité (0,1,0) que la classe… et utilisera :where() pour s'assurer que le sélecteur n'est pas plus spécifique que cela.

c'est tout!

C'est ainsi que nous profitons des capacités de gestion spécifiques modernes des pseudo-classes :is() et :where() et les capacités spécifiques de prévention des conflits obtenues lors de l'écriture de CSS au format BEM. Dans un avenir proche, une fois que :has() est soutenu par Firefox (il est actuellement pris en charge derrière le logo au moment de la rédaction), nous voulons peut-être l'associer à :where() pour défaire sa spécificité.

Que vous nommiez pleinement avec BEM ou non, j'espère que nous pouvons convenir que la spécificité du sélecteur est une bonne chose!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn