3
There are dreams, dry goods, WeChat search [Daiqian World] Pay attention to this Shuawanzhi who is still doing dishes in the early morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line interview complete test site, information and my series of articles.

background

Recently, when the boss was maintaining other people’s code, he found that the styles written by our team had different ideas and styles, which would increase the difficulty of subsequent maintenance. Therefore, the boss decided to unify the convention name specification, so he arranged for me to investigate and In practice, the following are the results of my research.

What is the BEM naming convention

BEM is a front-end CSS naming methodology proposed by the Yandex team. BEM is the abbreviation BlockElementModifier B represents a block, E represents an element, and M represents a modifier.

These three parts are usually connected __ and -- That is: . Block __ element-modifier {}

  • Block : Represents an independent block-level element, which can be understood as a functional component block. A block is an independent block. For example, the head is a block, and the form function input box is a block, and the block can be large or small.
  • Element : It is a part of Block that cannot be used independently. All Elements are closely related to Block. For example, an icon , then the icon is an element of the input box Block, and the icon is meaningless if it is separated from the Block of the input box.
  • Modifier : It is used to modify the block or element, indicating the change in appearance or behavior of the block or element. For example, the input box Block mentioned above, the border is highlighted when the mouse is hovered, then this highlighting effect should be realized by Modifier.

The green table above is block , blue means element , and red means modifier .

Why use BEM?

performance

The CSS engine looks up the style sheet, and matches each rule from right to left. The following code looks fast, but it is actually very slow. Usually we think that the browser works like this: find the unique ID element ul-id —> apply the style to the li element.

In fact: Match from right to left, traverse each li element on the page and determine its parent element

#ul-id li {}

So don't let your css exceed three levels.

Semantic

The key to BEM is that the name alone can tell other developers what a tag is for. By browsing the class attribute in the HTML code, you can understand how the modules are related: some are just components, some are descendants or elements of these components, and some are other forms or decorations of components symbol.

Examples of conventional nomenclature:

 <div class="article">
    <div class="body">
        <button class="button-primary"></button>
        <button class="button-success"></button>
    </div>
</div>

This way of writing can understand the meaning of each element from the DOM structure and class naming, but it cannot clarify its true hierarchical relationship. When defining css, you must also rely on hierarchical selectors to limit the scope of constraints to avoid cross-component style pollution.

Example of using the BEM naming method:

<div class="article">
    <div class="article__body">
        <div class="tag"></div>
        <button class="article__button--primary"></button>
        <button class="article__button--success"></button>
    </div>
</div>

Through the BEM naming method, the module level relationship is simple and clear, and there is no need to make too many level choices in css writing.

how to use?

Suppose we want to implement such a card function:

According to the above design drawing, we use the bem method to name the corresponding class , as shown below:

<div class="card">
    <img class="card__img" src="./img.jpg" alt="">
    <div class="card__content">
        <ul class="card__list">
            <li class="card__item card__item--active">手机</li>
            <li class="card__item">移动市场</li>
            <li class="card__item">科技</li>
        </ul>
        <p class="card__desc">商化前端是一个很有活力的团队,能学到很多知识,你心动了吗?</p>
        <a class="card__link" href="#">详细内容</a>
    </div>
</div>

Corresponding CSS structure:

.card{
  // 省略...
}
.card__img{
  // 省略...
}
.card__content {
  // 省略...
}
.card__list{
  // 省略...
}
.card__item {
  // 省略...
}
.card__item--active {
  // 省略...
}
.card__link{
  // 省略...
}
.card__link:hover{
  // 省略...
}

As can be seen from the above code, our style classes do not have any nesting relationship, and the nesting relationship is replaced by the way of naming.

Just started using bem easy to make when there is a problem, is to ul and li style written card__content__list and card__content__list__item because it better reflects the level of relations.

This is contrary to the BEM naming convention. The BEM naming contains only three parts, and the element name only occupies a part of them, so there cannot be multiple element names . This convention can prevent the problem of long naming when the hierarchy is deep.

We have to write card each style above. If card is replaced with a longer word, it will be too verbose. This is also one of the reasons why people don’t like bem, but this sass or less is a good solution. We can use & represent the root element, which can be changed to the following structure in less or sass:

.card{
  // 省略...
  &__img{
  // 省略...
  }
  &__content {
  // 省略...
  }
  &__list{
  // 省略...
  }
  &__item {
  // 省略...
  }
  &__item--active {
  // 省略...
  }
  &__link{
  // 省略...
  }
  &__link:hover{
  // 省略...
  }
}

Use of plug-ins

Similar to the eslint stylelint also has a configuration file .stylelintrc.js (there are other formats, here we take the js file as an example).

module.exports = {};

In order to let the friends write in compliance with the Bem specification, here we use the stylelint-selector-bem-pattern plug-in, which combines the plug-in postcss-bem-linter rules, which can be used to verify the BEM naming specification.

module.exports = {
  plugins: [
    'stylelint-selector-bem-pattern'
  ],
  "rules": {
       'plugin/selector-bem-pattern': {
          // 选择Preset Patterns,支持suit和bem两种,默认suit规范;
          // 不管哪种都需要手动指定,因为该插件未给源插件默认指定
          'preset': 'bem',
          /**
           * 自定义模式规则
           * 指定组合的选择器检查规则,其实就是指定class名称规则
           * 支持正则字符串、返回正则的函数、包含2个选项参数的对象等写法
           */
          componentSelectors: {
            // 只初始的选择器规则(可以理解为外层的class规则)
            initial: '^\\.{componentName}(?:__[-a-z]+)?(?:--[a-z]+)?$',
            // 可以理解为外层以内的选择器的规则,
            // 如果不指定,则跟initial同样的规则,
            // 注意这里配置的时候比上面少一个问号,
            // 是希望内层就不应该只有componentName作为选择器了
            combined: '^\\.{componentName}(?:__[-a-z]+)(?:--[a-z]+)?$'
          },
          "utilitySelectors": "^\\.u-[a-z]+$",
          ignoreSelectors: ['^\\.el-', '/deep/', '>>>', '^\\.icon-'],
          ignoreCustomProperties: [],
        }
   }
}

After the configuration is complete, in order to allow VsCode to give an error message, we need to add the stylelint plug-in to VsCode.

Finally, it is the git commit check

// package.json
{
    "husky": {
        "hooks": {
          "pre-commit": "lint-staged"
        }
    },
   "lint-staged": {
    "*.{vue,ts,tsx,js,jsx}": "eslint --fix",
    "*.{vue,css,less,sass,scss}": "stylelint --fix"
  },
}

This involves husky . If you don’t understand, you can Google for detailed information.

Actual combat

After the configuration is complete, we need to verify it by hand

First, we need to define a context so that the plugin knows to validate the CSS.

For example, we have the following html structure:

<div class="form form--theme-xmas">
  <input class="form__input" />
  <input class="form__submit form__submit--disabled" type="submit" />
</form>

The corresponding css should be written like this:

/** @define formWrapper */
.formWrapper{
  padding: 0 20px;
  box-sizing: border-box;
}
.formWrapper--line{
  display: none;
}
.formWrapper__form-item{
  display: flex;
  align-items: center;
  margin-bottom: 20px;
}

Here @define formWrapper declares a block formWrapper , which means that the style must formWrapper , otherwise an error will be reported.

If there are multiple blocks, we only need multiple @define statements.

/** @define Foo */
.Foo {}

/** @define Bar */
.Bar {}

If a class does not belong to any block, what should we do so that styleint will not report an error? Here we can add /** @end */ indicate the end of the block.

/** @define form */
.form{
  display: flex;
}
.form--theme-blue{
  text-align: center;
}
/** @end */

.isActive{
  display: flex;
}

If we want to ignore the verification of a certain block style, we can use the following syntax to ignore it:

/** @define MyComponent */

.MyComponent {
  display: flex;
}

/* postcss-bem-linter: ignore */
.no-flexbox .Component {
  display: block;
}

Summarize

One of the hardest parts of BEM is knowing where the scope starts and ends, and when to use or not to use it. With the accumulation of experience in continuous use, you will gradually know how to use it, and these problems will no longer be a problem. There is no good or bad technique, and the right one is the best.

refer to:
https://www.jianshu.com/p/54b000099217
https://juejin.cn/post/6844903672162304013#heading-1
https://segmentfault.com/a/1190000009953887
https://www.kancloud.cn/kancloud/sass-guidelin/48091
https://juejin.cn/post/6885302959303819271#heading-1

possible bugs of the 161aea40b062e1 code after deployment cannot be known in real time. In order to solve these bugs afterwards, a lot of time was spent on log debugging. By the way, I would like to recommend a useful BUG monitoring tool Fundebug .

comminicate

If you have dreams and dry goods, search for [Moving to the World] attention to this wise brush who is still doing dishes in the early morning.

This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line interview complete test site, information and my series of articles.


王大冶
68.1k 声望105k 粉丝