『精』CSS 小技巧之BEM规范

news2025/4/22 5:30:05

『精』CSS 小技巧之BEM规范.jpg

『精』CSS 小技巧之BEM规范

文章目录

  • 『精』CSS 小技巧之BEM规范
    • 一、什么是BEM?
    • 二、BEM要怎么用?
    • 三、不用BEM会少个胳膊吗?💊
    • 四、Sass与BEM的结合🎈
    • 五、块与修饰符应放在一块👿
    • 参考资料💘
    • 推荐博文🍗


一、什么是BEM?

BEM风格规范指的是 Block、Element、Modifier 这三者的简称,这个规范将 CSS 拆分成块、元素、修饰符,根本作用是帮助开发者快速理解HTML与 CSS 之间的关系。那么通过使用 BEM 能获得到什么好处呢?我罗列了下面几点:

  1. 如果我们想制作一个组件的新样式,比如改个字体/背景色,可以很容易地看到有哪些样式项已经存在,只需要新增一个修饰符即可,甚至可能意识到一开始就不需要编写任何样式,有一个预先存在的修饰符可以满足我们的需求。
  2. 得益于 CSS 命名语义化的好处,我们能够快速了解其 HTML 结构分布,一个元素依赖哪一个元素,在产品变更时快速更改其样式,并完全确信您的更改不会产生副作用
  3. 模块化的样式命名规则,能够最有效解决样式之间同名、继承、优先级等所带来的污染性问题,避免最后因为充斥着各种臃肿,而不敢触及修改遗留的各种未知样式,这其实给了开发人员一定的信心。
  4. 团队配合成本的降低,样式可读性的提高能够让成员之间能够快速复用已有的样式规则,而不需要再去编写一套样式。

在没有接触 BEM 之前,也许你会对我这罗列的这一堆优点一头雾水,这很正常让我们接着往下看,在看完本文的剩余内容时也许回过头你就能恍然大悟。
需要注意的是 BEM 并非是官方的风格规范,它是由Yandex团队开发,程序员之间约定俗成的一种契约规范,受众范围十分广泛,许多知名开源 UI 框架将其使用,如 Elementui、vant、uView-ui。但随着 tailwind 这类 CSS 框架的强势入局,BEM使用也有减少的趋势,毕竟只有在手动编写CSS代码的时候才用的上,如新起之秀,号称最完整Vue UI套件的 primevue。


二、BEM要怎么用?

要探究BEM怎么用,最简单的方法就是直接上手,让我们从编写一套有着丰富样式按钮组件开始,该组件包含最常见的颜色类型/大小切换功能。
可以看到属于 .btn 元素下的子项目,在命名时带上以父元素为头,__ 分割的命名,而按钮的不同状态颜色则通过基本样式名为头, -- 分割进行命名。以这样的命名方式,翻译过来就是基本样式名被称为块,__分割被称为元素,--分割则被称为修饰符。

<article class="btn-demo">
  <div class="btn btn--primary btn--large">
    <span class="btn__icon">$</span>
    <span class="btn__text">按钮</span>
  </div>
  <div class="btn btn--info">
    <span class="btn__icon">$</span>
    <span class="btn__text">按钮</span>
  </div>
  <div class="btn btn--mini">
    <span class="btn__icon">$</span>
    <span class="btn__text">按钮</span>
  </div>
  <div class="btn btn--warn">
    <span class="btn__icon">$</span>
    <span class="btn__text">按钮</span>
  </div>
  <div class="btn btn--danger">
    <span class="btn__icon">$</span>
    <span class="btn__text">按钮</span>
  </div>
</article>
@mixin mBtnType($m, $color,  $hoverColor, $activeColor, $fontColor: #FFF) {
  .btn--#{$m} {
    color: $fontColor;
    border-color: $color;
    background-color: $color;

    &:active, &:hover {
      color: $fontColor;
    }

    &:hover {
      border-color: $hoverColor;
      background-color: $hoverColor;
    }

    &:active {
      border-color: $activeColor;
      background-color: $activeColor;
    }
  }
}

.btn-demo {
  display: grid;
  grid-template: 30px / repeat(4, 25%);
  grid-auto-rows: 30px;
  grid-row-gap: 20px;
  justify-content: space-between;
  justify-items: center;
  position: fixed;
  left: 50%;
  top: 20%;
  width: 450px;
  transform: translateX(-50%);
}

.btn {
  $activeColor: #409EFF;

  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 80px;
  height: 32px;
  padding: 5px 10px;
  border: 1px solid #F0F0F0;
  border-radius: 4px;
  color: #333;
  background-color: #FFF;
  cursor: pointer;

  &:active, &:hover {
    color: $activeColor;
    border-color: #A0CFFF;
    background-color: #ECF5FF;
  }

  &:active {
    border-color: $activeColor;
  }

  &__icon {
    font-weight: bold;
  }
}

.btn--mini {
  width: 60px;
  height: 28px;
  font-size: .8em;
}

.btn--large {
  width: 100px;
  height: 40px;
  font-size: 1.1em;
}

@include mBtnType("primary", #409EFF, #79BBFF, #337ECC);
@include mBtnType("warn", #E6A23C, #EEBE77, #B88230);
@include mBtnType("danger", #F56C6C,  #F89898, #C45656);

示例中样式使用的是 Sass,如需查看 CSS 请安装 Sass 包将其转换成传统 CSS 代码。

# 安装Sass
npm i sass -g
# 将Sass编译成CSS
sass input.scss output.css

简单来说,BEM 最核心的写法就是用上 __-- 将样式命名进行区分。
2.1 按钮组件点击


三、不用BEM会少个胳膊吗?💊

这是个很冷笑话式的问题,在任何时间地点不使用BEM规范进行约束都不会让你少个胳膊少个腿,这些是约束自我的规则,其价值来自遵循它们,当然前提是你的项目规范支持你这么做,不然你的同事可能不介意帮你少个胳膊,哈哈😉
如果你不喜欢这么做,那大可不用纠结于此规范。
BEM模块化的规范必定会带来一些坏处,最明显的一个问题就是容易将名称命名过长,看起来臃肿而凌乱,这也是最常被用来反对 BEM 的论点,在我看来,这其实即使优点也是缺点,你也不希望这么一个选择器 p li .title {} 与你 HTML 结构命名一样的业务模块发生样式污染吧?
如果坚定了决心,那么在不使用BEM规范的情况下,还有什么比较好的CSS命名方法吗?以下面的示例演示,可以这么去做。

<article class="fruit-select">
  <div class="cell-list">
    <div class="cell-item">
      <span class="cell-text">香蕉</span>
      <input type="checkbox" class="cell-checkbox">
    </div>
    <div class="cell-item active">
      <span class="cell-text">榴莲</span>
      <input type="checkbox" class="cell-checkbox">
    </div>
    <div class="cell-item">
      <span class="cell-text">柚子</span>
      <input type="checkbox" class="cell-checkbox">
    </div>
  </div>
</article>

将HTML元素辅助的作用进行语义化,对CSS类名进行一个简单的命名,对于不同状态样式一块,考虑使用交集选择器进行编写。

.fruit-select {
  width: 200px;
  padding: 10px 0;
  border: 1px solid #666;
}

.cell-list {
  display: flex;
  flex-direction: column;
}

.cell-item {
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 40px;
  padding: 0 10px;
}

.cell-item + .cell-item {
  border-top: 1px solid #666;
}

.cell-item.active {
  color: #FFF;
  background-color: #FFA500FF;
}

当然这其实也是一个建议,至少在我没有接触到BEM规范之前的一段时间,我都是这么去书写我的代码。


四、Sass与BEM的结合🎈

BEM 毕竟只是应该风格规范,只要有需要手动编写样式的地方,就能发挥 BEM 的威力,将 Sass 与 BEM 搭配可大大提高开发效率,可谓是锦上添花。
在一开始的 二、BEM要怎么用? 示例代码中,就用到了 Sass,而 Sass 应用在前端框架中可以说是最常见的操作,接下来将完整的以 Vue + Sass 实现一个表格页面为例。

<script lang="ts" setup>
  /*
   * 组件名: bem
   * 组件用途: bem规范示例页
   * 创建日期: 2023/12/27
   * 编写者: XianZhe
   */
  import { reactive } from "vue";

  const $state = reactive({
    source: [
      ["阿联酋迪拉姆", 193.89, 192.29, 195.25, 198.79, 193.42, "2023-12-27"],
      ["澳大利亚元", 486.94, 486.44, 490.2, 491.62, 485.15, "2023-12-27"],
      ["加拿大元", 539.83, 539.28, 543.45, 545.02, 538.58, "2023-12-27"],
      ["瑞士法郎", 834.27, 833.6, 840.13, 842.47, 832.27, "2023-12-27"],
      ["丹麦克朗", 105.47, 105.28, 106.31, 106.82, 105.11, "2023-12-27"],
      ["欧元", 786.92, 780.98, 792.43, 794.48, 784.52, "2023-12-27"],
      ["英镑", 905.71, 904.78, 911.78, 914.41, 904.36, "2023-12-27"],
      ["港币", 91.34, 91.32, 91.68, 91.68, 90.9, "2023-12-27"],
      ["印尼卢比", 0.0461, 0.0447, 0.0466, 0.0482, 0.0461, "2023-12-27"],
      ["日元", 4.9913, 4.9912, 5.0247, 5.0267, 4.9951, "2023-12-27"],
      ["美元", 713.21, 713.05, 716.05, 716.05, 710.02, "2023-12-27"]
    ]
  });
</script>

<template>
  <section id="bem" class="bem">
    <header class="bem__hd">
      <h2>BEM规范表格页</h2>
    </header>
    <main class="bem__bd">
      <table class="bem__table">
        <thead class="bem__table__hd">
        <tr>
          <th>货币名称</th>
          <th>现汇买入价</th>
          <th>现钞买入价</th>
          <th>现汇卖出价</th>
          <th>现钞卖出价</th>
          <th>中行折算价</th>
          <th>发布日期</th>
          <th>操作</th>
        </tr>
        </thead>
        <tbody class="bem__table__bd">
        <tr v-for="(item, index) in $state.source" :key="index">
          <td v-for="sitem in item" :key="sitem">{{ sitem }}</td>
          <td>
            <div class="bem__table__operation">
              <span class="bem__table__operation-btn bem__table__operation-btn--danger">删除</span>
              <span class="bem__table__operation-btn bem__table__operation-btn--primary">详情</span>
            </div>
          </td>
        </tr>
        </tbody>
      </table>
    </main>
    <main class="bem__ft">
      <button class="bem__btn">你好</button>
    </main>
  </section>
</template>

<style lang="scss" scoped>
  .bem {
    &__bd {
      margin-bottom: 20px;
    }

    &__table {
      border-collapse: collapse;
      border: 1px solid #000;

      &__hd {
        background-color: #F0F0F0;
      }

      &__bd {
        tr {
          border-top: 1px solid #000;
        }
      }

      &__operation {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0 10px;

        &-btn {
          cursor: pointer;
        }

        &-btn--primary {
          color: #409EFF;
        }

        &-btn--danger {
          color: #F56C6C;
        }
      }

      td {
        min-width: 100px;
        text-align: center;
      }
    }

    &__btn {
      width: 100px;
      height: 38px;
      border: unset;
      color: #FFF;
      border-radius: 4px;
      background-color: #409EFF;
      cursor: pointer;

      &:hover {
        background-color: #79BBFF;
      }

      &:active {
        background-color: #337ECC;
      }
    }
  }
</style>

4.1 BEM规范表格页
再来看看 ELement-ui 关于 BEM 应用的部分源码,以供更多参考,此源码取自 ELement-ui 级联组件部分。Element-ui 源码对于 BEM 的应用比较高级,简单来说就是利用 Sass 的 Mixin(混合),将 BEM 拆分成 b、e、m 三者的混合函数,再使用 include 注入到每一个组件之中。

@include b(cascader) {
  @include set-component-css-var('cascader', $cascader);

  display: inline-block;
  vertical-align: middle;
  position: relative;
  font-size: getCssVar('font-size', 'base');
  line-height: map.get($input-height, 'default');
  outline: none;

  &:not(.is-disabled):hover {
    .#{$namespace}-input__wrapper {
      cursor: pointer;
      box-shadow: 0 0 0 1px getCssVar('input', 'hover-border-color') inset;
    }
  }

  .#{$namespace}-input {
    display: flex;
    cursor: pointer;

    .#{$namespace}-input__inner {
      text-overflow: ellipsis;
      cursor: pointer;
    }

    .#{$namespace}-input__suffix-inner {
      .#{$namespace}-icon {
        height: calc(100% - 2px);

        svg {
          vertical-align: middle;
        }
      }
    }
    ...
  }
  ...
}

与之类似的还有Less这个CSS预处理器,使用起来和Sass是一样的道理。


五、块与修饰符应放在一块👿

看到下面这个选择器.cell__item--active,你会期待什么,正确的做法是将.cell__item--active.cell__item 放到一块,不能因为样式一样则直接使用,公共样式应该改用其他选择器样式。

<article class="cell__list">
  <div class="cell__item">
    <p class="cell__item--active">List item 1</p>
    <button>按钮</button>
  </div>
  <div class="cell__item">...</div>
</article>

还有存在这种情况,不同的块覆盖同一层级的修饰符,不要这么做。

<style>
  .block__btn {
    color: #333;
    background-color: #FFF;
    border: unset;
  }
  .block__inner .block__btn--primary {
    background-color: #409EFF;
  }
</style>
<div class="block">
  <div class="block__inner">
    <button class="block__btn block__btn--primary">按钮</button>
  </div>
</div>
  • 切勿覆盖不相关块中的修饰符。
  • 明确作用域原则,避免搞砸对 BEM 非常有帮助的特异性。

参考资料💘

🍅因发布平台差异导致阅读体验不同,源文贴出:《CSS 小技巧之BEM规范》

  • 网络文献:
    • getbem
    • css-tricks
    • why use bem?

推荐博文🍗

  • 『速查手册』HTML 语义化标签 | 语义化标签必要性?
  • 『干货』WebStorm代码模板配置大全

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1346230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis经典五大类型源码及底层实现(一)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术&#x1f525;如果感觉博主的文章还不错的…

年度总结|存储随笔2023年度最受欢迎文章榜单TOP15-part1

原创 古猫先生 存储随笔 2023-12-31 08:31 发表于上海 回首2023 2-8月份有近半年时间基本处于断更状态 好在8月份后小编没有松懈 &#xff08;虽然2023年度总结&#xff0c;更像是近4个月总结&#xff09; 本年度顺利加V啦&#xff01; 感谢各位粉丝朋友的一路支持与陪伴 …

Linux之磁盘分区,挂载

Linux分区 分区介绍 对linux来说无论有几个分区&#xff0c;分给哪个目录使用&#xff0c;归根结底只有一个根目录&#xff0c;linux中每个分区都是用来组成整个文件系统的一部分。linux采用“载入"的处理方法&#xff0c;他的整个文件系统中包含一整套的文件和目录&…

osg::DrawElements*系列函数及GL_QUAD_STRIP、GL_QUADS绘制四边形效率对比

目录 1. 前言 2. osg::DrawElements*系列函数用法说明 3. GL_QUADS、GL_QUAD_STRIP用法及不同点 4. 效率对比 5. 总结 6. 参考资料 1. 前言 利用osg绘制图元&#xff0c;如&#xff1a;三角形、四边形等&#xff0c;一般用osg::PrimitiveSet类。其派生出了很多子类&#…

【网络安全 | Misc】miss_01 太湖杯

解压时提示输入密码&#xff1a; 如果 frFlags 或 deFlags 不为0会导致zip的伪加密 将deFlags的值修改为0 将9改为0&#xff0c;另存为123.zip&#xff1a; 即可绕过加密&#xff1a; 得到一个zip一个docx&#xff0c;但zip需要密码&#xff1a; 因此看docx有无敏感信息&#x…

面向对象基础-类与对象-封装

1、类与对象 1.1 概念 类&#xff1a;类是一个抽象的概念&#xff0c;用于描述一类对象的特点。 对象&#xff1a;根据类的概念所创造的实体。 【思考】一个对象可以没有对应的类嘛&#xff1f; 不可以&#xff0c;因为必须现有类才能创建对象。 1.2 类的内容 类中最基础的内容…

x-cmd pkg | fzf - 命令行模糊查找器

目录 简介首次用户功能特点竞品和相关作品进一步阅读 简介 fzf 是一个由 Go 编写的命令行模糊搜索工具&#xff0c;用于在大量文本数据中快速定位和选择内容&#xff0c;可以与任何列表一起使用&#xff08;e.g. 文件、命令历史记录、进程、主机名、书签、git 提交等&#xff…

鲲志说:向我乘风破浪,好事多磨的2023致敬!(感恩有礼,感谢有你)

伴随着2023最后一个工作日的结束&#xff0c;也终于要给一年的工作划上一个结尾了&#xff0c;当然&#xff0c;也要给自己一个交代&#xff0c;给自己一个年度总结 2023年&#xff0c;大的挫折也是有的&#xff0c;但我相信好事多磨&#xff0c;总的来说是事业型的一年&#x…

华为ensp网络设计期末测试题-复盘

网络拓扑图 地址分配表 vlan端口分配表 需求 The device is running!<Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]un in en Info: Information center is disabled. [Huawei]sys S1 [S1]vlan 99 [S1-vlan99]vlan 100 [S1-vlan100]des IT [S1-…

关于“Python”Django 管理网站的核心知识点整理大全52

目录 注意 18.2.2 激活模型 settings.py 18.2.3 Django 管理网站 1. 创建超级用户 注意 2. 向管理网站注册模型 admin.py 注意 3. 添加主题 Climbing。 18.2.4 定义模型 Entry models.py 18.2.5 迁移模型 Entry 18.2.6 向管理网站注册 Entry admin.py 往期快速…

十三:爬虫-Scrapy框架(下)

一&#xff1a;各文件的使用回顾 1.items的使用 items 文件主要用于定义储存爬取到的数据的数据结构&#xff0c;方便在爬虫和 Item Pipeline 之间传递数据。 items.pyimport scrapyclass TencentItem(scrapy.Item):# define the fields for your item here like:title scr…

c++简易AI

今天小编一时雅兴大发&#xff0c;做了一个c的简易AI&#xff0c;还是很垃圾的&#xff01; 题外话&#xff08;每期都会有&#xff09;&#xff1a;我的蛋仔名叫酷影kuying&#xff0c;大家能加我好友吗&#xff1f; 上代码咯&#xff01; #include<bits/stdc.h> #in…

2023年终总结丨很苦,很酷!

文章目录 个人简介丨了解博主写在前面丨博主介绍年终总结丨博主成就年终总结丨博主想说年终总结丨学习芝士年终总结丨未来展望写在后面丨新年快乐 个人简介丨了解博主 主页地址&#xff1a;https://blog.csdn.net/m0_68111267 荣誉身份 ⭐2022年度CSDN 社区之星 Top6 ⭐2023年…

基于NASM搭建一个能编译汇编语言的汇编软件工具环境(利用NotePad++)

文章目录 一、创建汇编语言源程序二、Notepad的下载、安装、使用三、下载和安装编译器NASM3.1 下载NASM编译器3.2 安装并配置环境变量 四、编译汇编语言源程序&#xff08;使用命令&#xff09;五、下载和使用配套源码及工具六、将编译功能集成到Notepad 一、创建汇编语言源程序…

vue3中pinia的使用及持久化(详细解释)

解释一下pinia&#xff1a; Pinia是一个基于Vue3的状态管理库&#xff0c;它提供了类似Vuex的功能&#xff0c;但是更加轻量化和简单易用。Pinia的核心思想是将所有状态存储在单个store中&#xff0c;并且将store的行为和数据暴露为可响应的API&#xff0c;从而实现数据&#…

[设计模式 Go实现] 创建型~工厂方法模式

工厂方法模式使用子类的方式延迟生成对象到子类中实现。 Go中不存在继承 所以使用匿名组合来实现 代码实现 package factorymethod//Operator 是被封装的实际类接口 type Operator interface {SetA(int)SetB(int)Result() int }//OperatorFactory 是工厂接口 type OperatorF…

国图公考:研究生可以考选调生吗?

研究生可以报考选调生吗?当然是可以的&#xff0c;但是同样需要满足一定的条件才可以。 除本科生外&#xff0c;具有硕士、博士学位的考生均可申请考试。但是&#xff0c;除了满足应届毕业生的身份&#xff0c;还需要满足年龄限制。一般来说&#xff0c;本科生不超过25岁&…

文件批量整理,文件归类整理,文件批量归类

我们每天都要面对无数的文件&#xff0c;从工作报告、个人照片到电影和音乐。如何有效地管理和归类这些文件&#xff0c;成为了我们日常生活和工作中所要处理的。今天&#xff0c;小编就给大家介绍一款简单易用的工具——文件批量改名高手&#xff0c;助你轻松实现文件批量归类…

基于DBNetpp的文本检测的仪表盘读数识别

一个不知名大学生&#xff0c;江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2023.12.31 Last edited: 2023.12.31 祝自己生日快乐啦&#xff01;&#xff01;&#xff01;&#xff01; 目录 算法设计 &#xff08;1&…

【逗老师的无线电】ICOM IC-705终端模式Terminal Mode直连反射器配置-内置网关IP直连篇

各位友台大家好呀&#xff0c;逗老师最近整了一台IC-705&#xff0c;最吸引人的莫过于这玩意可以IP直连反射器。下面简单介绍一下这个功能和其配置方法 目录 一、功能二、依赖条件三、配置3.1、IC-705连接WIFI3.2、配置Terminal Mode3.2.1、点击MENU进入菜单&#xff0c;翻到第…