Maison >interface Web >tutoriel CSS >Apprivoiser la cascade avec des sélecteurs CSS BEM et modernes
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.
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.
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.
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
:where()
<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!
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 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!