查看原文
其他

现代CSS:使用 CSS @scope 替代 BEM

小懒 FED实验室 2024-02-12
关注下方公众号,获取更多现代CSS系列文章

日常 Web 开发中,前端工程师经常遇见或者最有挑战的事情之一就是 CSS 命名约定了。随着 Block Element Modifier (BEM) 规范的流行,开发者者开始习惯以可维护的模式组织样式。

好消息!近期发布的 Chrome 118 版本已经实现对 CSS @scope 的支持,以允许在样式表中对样式进行区块级作用域,进一步提高 BEM 的优势。这使样式更易于维护,同时提供对影响任何前端应用程序的 CSS 层叠的更严格的控制。

在本文中,我们将探讨如何在 Chrome 中使用 @scope 功能,以及如何在前端项目中使用它来替代 BEM。

主要内容如下:

  • CSS @scope 介绍
  • BEM 介绍
  • 使用 CSS @scope 重构 BEM

1.CSS @scope 介绍

对于 CSS 样式隔离,CSS 作用域大家都不陌生,主流的方案包括 CSS Modules、CSS in JS、Shadow DOM、Vue Scoped Styles 等,这些方案都有各自的优缺点,但是都不是原生的 CSS 方案,使用和版本升级需要一些学习成本。

Chrome 118 版本中,已经实现对 CSS @scope 的支持,@scope 特性可以为CSS样式创建区块级作用域,这使开发人员对CSS样式更有控制权,我们现在可以直接在 CSS 文件中具体定义视图部分的作用域。

@scope 语法规则:

@scope [(<scope-start>)]? [to (<scope-end>)]? {
  <rule-list>
}

@scope兼容性:

@scope 示例:

请看下面的 HTML 示例:

<main class="container">
  <section class="section section-one">
    <h2>First</h2>
    <p>first section paragraph text</p>
  </section>
  <section class="section section-two">
    <h2>Second</h2>
    <p>second section paragraph text</p>
  </section>
</main>

在此 HTML 中,我们可以使用以下方法对 .section-two 样式区域中的元素进行样式设置:

.container {
  max-width600px;
  margin0 auto;
  .section {
    display: flex;
    flex-direction: column;
    border1px solid #ccc;
    border-radius5px;
    margin-bottom10px;
    & h2 {
      font-size16px;
      line-height36px;
      text-align: center;
      background-color#ccc;
      margin0;
    }
    & p {
      font-size24px;
      text-align: center;
    }
  }
}

@scope (.section-two) {
  p {
    color#f00;
  }
}

效果如下:

使用 @scope,还可以创建一个 "甜甜圈" 作用域,为一组样式及其中的元素定义起始和结束部分。使用上述相同的 HTML,"甜甜圈"作用域可以定义从 .container 的起始区域到 .section-two 样式区域的样式,将上面的 @scope 样式做如下替换:

@scope (.container) to (.section-two) {
  p {
    color#00f;
  }
}

效果如下:

令人愉快的是,它的功能与使用 BEM 规范非常相似,但代码量更少。

2.BEM 介绍

BEM 是一种简单的命名约定,可使前端代码更易于阅读、理解、使用和扩展。它既稳健又清晰。

我们都知道,HTML 文档如果没有良好的结构会有多混乱。如果再加上一个糟糕的 CSS 类命名规范,你的代码库就会变得难以理解、漏洞百出,甚至难以扩展。

遵循 BEM 命名规范,不仅能简化 CSS 文件的结构,还能简化 HTML 文档的结构。我们可以使用独立的代码块和 CSS 选择器,以组件驱动的方式进行思考,从而使我们的代码具有可重用性和模块性。

要使用 BEM,我们只需遵循其命名规则即可!

  • B 代表块(block)。区块是一个独立的实体。例如卡片组件
  • E 代表元素(Element)。元素是区块的一部分,在语义上与区块相关联,本身没有任何意义。
  • M 代表修改器(Modifier)。它只是一个标记,可以修改元素或块的外观或行为

看下面的 HTML 示例:

<main class="container">
  <section class="container__section-one">
    <h2 class="container__section-one--title">First</h2>
    <p class="container__section-one--first-line">first section paragraph text</p>
  </section>
  <section class="container__section-two">
    <h2 class="container__section-two--title">Second</h2>
    <p class="container__section-two--first-line">second section paragraph text</p>
  </section>
</main>

BEM 的扩展性很好,尤其是在使用 SASS 对样式进行分组,并使用 "&" 运算符创建类似样式的情况下:

.container {
  &__section-one {

    &--title {
      /* rule */
    }

    &--first-line {
      /* rule */
    }
  }
}

使用 BEM 的痛点在于,在大型项目中,会产生非常大的 CSS 或者 SASS 文件,而这些文件会带来难以估量的维护和管理成本。下面我们将探讨使用 @scope 替代 BEM 样式,使样式定义更小、更易于管理。

3.使用 CSS @scope 重构 BEM

要展示使用 @scope 的优势,最好的方法是在使用 React 等主流框架或库的应用程序中使用。为了简单演示,我们还是使用上面的示例,将 section-one 区块的标题样式使用 @scope 重写:

/* replaced */
/* container__section-one--title  {
  color: #f00;
} */


/* donut scope */
@scope (.container) to (.section-two) {
  h2 {
    color#f00;
  }
}

这样做的另一个好处是,HTML 结构更简洁,单行字数更小,更容易阅读。改为 @scope 后的 HTML 代码:

<main class="container">
  <section class="section-one">
    <h2>First</h2>
    <p>first section paragraph text</p>
  </section>
  <section class="section-two">
    <h2>Second</h2>
    <p>second section paragraph text</p>
  </section>
</main>

4.@scope 的其他优点

除了将 BEM 重构为 @scope 的优点外,使用 @scope 还可以更好地控制 CSS 级联。CSS 级联是一种算法,它定义了网络浏览器如何处理组成 HTML 页面上元素的样式条件。

在处理任何前端项目时,当样式产生奇怪的结果时,开发人员可能不得不适应级联产生的副作用。使用 @scope,可以通过对元素进行严格的范围限定来控制级联的副作用。

<style>
div {
  padding: 10px;
  border-radius: 5px;
}
.light {
  background: #ccc;
  & a {
    color: #f00;
  }
}
.dark {
  background: #333;
  & a {
    color: #00f;
  }
}
</style>
<div class="light">
  <p><a href="#">First Level</a></p>
  <div class="dark">
    <p><a href="#">Second Level</a></p>
    <div class="light">
      <p><a href="#">Third Level</a></p>
    </div>
  </div>
</div>

效果如下:

我们发现第二次的 .light 颜色并没有生效,因为 .light.dark 的权重是一样的,无法实现覆盖。使用 @scope 改进后:

<style>
div {
  padding: 10px;
  border-radius: 5px;
}
@scope (.light) {
  :scope {
    background-color: #ccc;
  }
  a {
    color: #f00;
  }
}
@scope (.dark) {
  :scope {
    background-color: #333;
  }
  a {
    color: #00f;
  }
}
</style>

效果如下:

总结

在这篇文章中,我们探讨了如何将 BEM 风格的应用程序重构为使用 Chrome 浏览器新推出的 @scope 功能。我们介绍了 @scope 的工作原理,然后将一个简单的示例从 BEM 重构为 @scope。

新的 @scope 功能可能对前端开发人员来说是一个巨大的胜利,被所有现代浏览器所支持,这可能需要一些时间。但在此之前,它绝对是一个有趣的功能,并且对于样式化前端项目非常有帮助。如果你手上有内部或者系统类项目,快快动手试用起来吧。

如果本文对你有帮助,欢迎一键三连,转转转!

大家都在看

继续滑动看下一个

现代CSS:使用 CSS @scope 替代 BEM

小懒 FED实验室
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存