搜索
首页web前端css教程用BEM和Modern CSS选择器驯服级联

Taming the Cascade With BEM and Modern CSS Selectors

BEM。如同前端开发领域中几乎所有技术一样,使用 BEM 格式编写 CSS 可能会引起两极分化。但在我的 Twitter 社交圈中,它至少是更受欢迎的 CSS 方法之一。

我个人认为 BEM 很好,我认为你应该使用它。但我也能理解你为什么可能不使用它。

无论你对 BEM 的看法如何,它都提供了一些好处,最大的好处是它有助于避免 CSS 级联中的特异性冲突。这是因为,如果使用得当,任何以 BEM 格式编写的选择器都应该具有相同特异性分数 (0,1,0)。多年来,我已经为许多大型网站设计了 CSS(想想政府、大学和银行),正是这些大型项目让我发现 BEM 真正闪耀的地方。当您确信正在编写或编辑的样式不会影响网站的其他部分时,编写 CSS 会更有趣。

实际上,在某些情况下,添加特异性被认为是完全可以接受的。例如::hover:focus 伪类。它们的特异性分数为 0,2,0。另一个是伪元素——例如 ::before::after——它们的特异性分数为 0,1,1。不过,在本文的其余部分,让我们假设我们不希望出现任何其他特异性蔓延。?

但我并不是真的想向你推销 BEM。相反,我想谈谈我们如何将它与现代 CSS 选择器(例如 :is():has():where() 等)结合使用,以获得更强的级联控制。

现代 CSS 选择器是什么?

CSS 选择器级别 4 规范为我们提供了一些强大且相对较新的选择元素的方法。我最喜欢的一些包括 :is():where():not(),它们都受所有现代浏览器支持,并且现在几乎可以在任何项目中安全使用。

:is():where() 基本相同,只是它们对特异性的影响不同。具体来说,:where() 的特异性分数始终为 0,0,0。是的,即使是 :where(button#widget.some-class) 也没有特异性。同时,:is() 的特异性是其参数列表中特异性最高元素的特异性。因此,我们已经有了可以使用的两个现代选择器之间在级联整理方面的区别。

功能强大的 :has() 关系伪类也正在迅速获得浏览器支持(在我看来,这是自 Grid 以来 CSS 最大的新功能)。但是,在撰写本文时,:has() 的浏览器支持还不够好,还不能用于生产环境。

让我在我的 BEM 中添加一个伪类……

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

糟糕!看到那个特异性分数了吗?记住,使用 BEM,我们理想情况下希望我们的选择器都具有 0,1,0 的特异性分数。为什么 0,2,0 不好?考虑一个类似的扩展示例:

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

即使第二个选择器在源代码顺序中最后出现,第一个选择器更高的特异性 (0,1,1) 也会胜出,并且 .something--special 元素的颜色将设置为红色。也就是说,假设您的 BEM 编写正确,并且所选元素在 HTML 中同时应用了 .something 基类和 .something--special 修饰符类。

如果使用不当,这些伪类可能会以意想不到的方式影响级联。正是这些不一致之处可能会在以后造成麻烦,尤其是在更大更复杂的代码库中。

哎呀。那现在怎么办?

还记得我刚才说的 :where() 及其特异性为零的事实吗?我们可以利用这一点:

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

此选择器的第一部分(.something)获得其通常的特异性分数 0,1,0。但是 :where()——以及其中的所有内容——的特异性为 0,不会进一步增加选择器的特异性。

:where() 允许我们嵌套

那些不像我那样关心特异性的人(公平地说,可能很多人如此)在嵌套方面一直做得很好。通过一些随意的键盘敲击,我们可能会得到这样的 CSS(请注意,我使用 Sass 简洁起见):

<code>.card { ... }

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

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

在这个例子中,我们有一个 .card 组件。当它是一个“特色”卡片(使用 .card--featured 类)时,卡片的标题和图片需要不同的样式。但是,正如我们现在所知,上面的代码导致的特异性分数与我们系统的其余部分不一致。

一个顽固的特异性狂热者可能会这样做:

<code>.card { ... }
.card--featured { ... }
.card__title { ... }
.card__title--featured { ... }
.card__img { ... }
.card__img--featured { ... }</code>

还不错,对吧?坦率地说,这是漂亮的 CSS。

不过,HTML 也有缺点。经验丰富的 BEM 作者可能痛苦地意识到,需要复杂的模板逻辑来有条件地将修饰符类应用于多个元素。在这个例子中,HTML 模板需要有条件地将 --featured 修饰符类添加到三个元素(.card.card__title.card__img),但在现实世界的例子中可能更多。有很多 if 语句。

:where() 选择器可以帮助我们编写更少的模板逻辑——以及更少的 BEM 类——而不会增加特异性级别。

<code>.card { ... }
.card--featured { ... }

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

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

以下是 Sass 中的相同内容(注意尾随的与号):

<code>.card { ... }
.card--featured { ... }
.card__title { 
  /* 等 */ 
  :where(.card--featured) & { ... }
}
.card__img { 
  /* 等 */ 
  :where(.card--featured) & { ... }
}</code>

您是否应该选择这种方法而不是将修饰符类应用于各种子元素,这取决于个人喜好。但至少 :where() 现在给了我们选择!

非 BEM HTML 怎么办?

我们生活在一个不完美的世界里。有时您需要处理超出您控制范围的 HTML。例如,注入您需要设置样式的 HTML 的第三方脚本。这些标记通常不是使用 BEM 类名编写的,在某些情况下,这些样式根本不使用类,而是 ID!

同样,:where() 也可以帮我们解决这个问题。此解决方案略显笨拙,因为我们需要引用 DOM 树中我们知道存在的某个元素的类。

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

引用父元素感觉有点冒险和限制性。如果该父类发生更改或由于某种原因不存在怎么办?更好的(但可能同样笨拙的)解决方案是改用 :is()。记住,:is() 的特异性等于其选择器列表中最特异的选择器。

因此,我们可以使用 :is() 引用一个我们知道(或希望!)存在的类,而不是像上面的例子那样使用 :where() 引用它。

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

始终存在的 body 将帮助我们选择 #widget 元素,并且在同一个 :is() 中存在 .dummy-class 类会使 body 选择器具有与类相同的特异性分数 (0,1,0)… 并且使用 :where() 确保选择器不会比这更具体。

就这样!

这就是我们如何利用 :is():where() 伪类的现代特异性管理功能以及使用 BEM 格式编写 CSS 时获得的特异性冲突预防功能。在不久的将来,一旦 :has() 获得 Firefox 支持(在撰写本文时,它目前在标志后面受支持),我们可能希望将其与 :where() 配对以撤消其特异性。

无论您是否完全采用 BEM 命名,我希望我们都能同意选择器特异性的一致性是一件好事!

以上是用BEM和Modern CSS选择器驯服级联的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
模拟鼠标运动模拟鼠标运动Apr 22, 2025 am 11:45 AM

如果您曾经在现场演讲或课程中必须显示一个互动动画,那么您可能知道它并不总是那么容易与您的幻灯片进行互动

通过Astro Action和Fuse.js为搜索提供动力通过Astro Action和Fuse.js为搜索提供动力Apr 22, 2025 am 11:41 AM

对于Astro,我们可以在构建过程中生成大部分网站,但是有一小部分服务器端代码可以使用Fuse.js之类的搜索功能来处理搜索功能。在此演示中,我们将使用保险丝搜索一组个人“书签”

未定义:第三个布尔值未定义:第三个布尔值Apr 22, 2025 am 11:38 AM

我想在我的一个项目中实现一条通知消息,类似于您在保存文档时在Google文档中看到的信息。换句话说,一个

捍卫三元声明捍卫三元声明Apr 22, 2025 am 11:25 AM

几个月前,我正在使用黑客新闻(就像一个人一样),并且遇到了一篇(现已删除的)文章,内容涉及不使用if语句。如果您是这个想法的新手(就像我

使用网络语音API进行多语言翻译使用网络语音API进行多语言翻译Apr 22, 2025 am 11:23 AM

自科幻小说以来,我们就幻想着与我们交谈的机器。今天这很普遍。即便如此,制造的技术

JetPack Gutenberg块JetPack Gutenberg块Apr 22, 2025 am 11:20 AM

我记得当古腾堡被释放到核心时,因为那天我在WordCamp我们。现在已经过去了几个月,所以我想我们越来越多的人

在VUE中创建可重复使用的分页组件在VUE中创建可重复使用的分页组件Apr 22, 2025 am 11:17 AM

大多数Web应用程序背后的想法是从数据库中获取数据,并以最佳方式将其呈现给用户。当我们处理数据时

使用'盒子阴影”和剪辑路径一起使用'盒子阴影”和剪辑路径一起Apr 22, 2025 am 11:13 AM

让我们对您可以做一些有意义的事情做一些逐步的情况,但是您仍然可以用CSS欺骗来完成它。在这个

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能