『精』CSS 小技巧之BEM规范

『精』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代码模板配置大全

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android Matrix画布Canvas旋转Rotate,Kotlin

Android Matrix画布Canvas旋转Rotate&#xff0c;Kotlin private fun f1() {val originBmp BitmapFactory.decodeResource(resources, R.mipmap.pic).copy(Bitmap.Config.ARGB_8888, true)val newBmp Bitmap.createBitmap(originBmp.width, originBmp.height, Bitmap.Config.…

vscode调用HTML文件

vscode实现对HTML文件调用 创建html文件下载拓展内容点击拓展查找需要的拓展 导入html代码设置默认打开浏览器运行结果参考文献 做数据库课设的内容,尝试一些自己没有接触过的东西,了解如何创建一个网站以及数据库的一个应用 创建html文件 创建一个html的文件,加入后缀名 下…

docker搭建minio集群,集群分享文件URL踩坑问题

一、环境准备 3台机器&#xff0c;Ip地址依次为IP1,IP2,IP3二、设置服务器时间同步 Minio集群需要各个节点的时间保持同步&#xff0c;使用NTP作为时间同步服务&#xff0c;这里以Minio-1&#xff08;IP1&#xff09;为上游服务器&#xff0c;其它2个节点为下游服务器&#x…

HarmonyOS 组件通用属性之通用事件 文档参数讲解(点击事件)

我们组件中 会有很多通用的信息和方法 那么 首先 我们看通用事件 通用事件中 最常用的就是我们的点击事件 比如说 我们之前常写的 组件.onClick(()>{//事件逻辑 })但是 我们之前 都没有用它接参数 我们可以这样 Button("跳转").onClick((ewat: ClickEvent)>…

Matplotlib_艺术画笔见乾坤

文章目录 一、概述&#xff1a;1.matplotlib的三层api2.Artist的分类3.matplotlib标准用法 二、自定义你的Artist对象1.Artist属性 在图形中的每一个元素都对应着一个matplotlib Artist&#xff0c;且都有其对应的配置属性列表。2.属性调用方式 三、基本元素 - primitives1.2DL…

[MySQL] MySQL中的事物

本片文章对MySQL中的事物进行了详解。其中包含了事物的特性、为什么要有事物、查看事物版本支持、事物常见操作、事物的隔离界别等等内容进行详细举例解释。同时还深入讲解了事物的隔离性&#xff0c;模拟实现MVCC多版本并发控制&#xff0c;也讲解了RR和RC的本质区别。希望本篇…

汽车保养软件app开发步骤

“增强您的动力&#xff0c;为您的旅程加油——每一刻都讲述着关爱的故事。构建汽车维护软件app&#xff0c;为您的车辆提供数字化的维修站&#xff0c;从而开启长寿之路。智能驾驶、互联驾驶、自信驾驶。” 疯狂地搜索旧收据并猜测上次换油时间的日子已经一去不复返了。如果您…

LINUX 抓包工具Tcpdump离线安装教程

本次教程基于内网环境无法访问网络使用安装包进行安装抓包工具 1、首先给大家看下一共有6个安装包&#xff0c;依次进行解压&#xff0c;包我就放到csdn上了&#xff0c;需要的可以联系我进行下载 2打包然后传到服务器任意一个目录下&#xff0c;进入到当前目录&#xff0c;然后…

Maven下载和安装的详细教程

文章目录 一、Maven下载和安装1.1 下载 Maven1.2 配置环境变量 参考资料 一、Maven下载和安装 1.1 下载 Maven 打开 Maven 的官方网站Maven – Download Apache Maven&#xff0c;下载最新版本的 Maven 在可选择的版本中&#xff0c;不同版本的区别在于: binary是已经编译过的…

【网络面试(2)】DNS原理-域名和IP地址的查询转换

从上一篇博客我们得知浏览器是如何生成了HTTP消息了&#xff0c;但是浏览器作为应用程序&#xff0c;是不具备向网络中发送请求的能力&#xff0c;而是需要委托给操作系统的内核协议栈来发送请求。在委托协议栈之前&#xff0c;浏览器还要做的一件事情就是将域名转换为IP地址。…

Pytest 项目结合Jenkins

一、window安装centos7虚拟机 参考网上其他教程 二、Linux安装Jenkins 进入jenkins.io网址&#xff0c;点击download&#xff0c;选择CentOS版本 1、Linux中安装java环境和git Jenkins的运行需要java环境&#xff1b;安装git是为代码上传给仓库做准备&#xff1b; yum - y…

AI与数字化映像:颜值开端,功能至上_光点科技

在人工智能的浪潮中&#xff0c;AI数字人的兴起正成为一个不可忽视的现象。随着ChatGPT等生成式AI算法的进步&#xff0c;AIGC&#xff08;人工智能生成内容&#xff09;的应用呈现出爆发性增长&#xff0c;不仅在技术圈引起广泛关注&#xff0c;也为元宇宙及其相关产业链带来了…

读算法霸权笔记08_反馈

1. 关开门 1.1. clopening 1.2. 指的是一个职员工作到很晚&#xff0c;关闭门店或者咖啡店&#xff0c;几小时后又在天亮之前回来开门 1.3. 极度不规律的工作时间安排越来越常见 1.3.1. 首当其冲的是星巴克、麦当劳和沃尔玛等企业的低薪职工 1.3.2. 不规律的工作时间安排是…

大一c语言期末复习题

第16题&#xff1a; 答案&#xff1a; #include<stdio.h> void hello_world(void) {printf("Hello,world!\n"); } void three_hellos(void) {int i 0;for (i 0; i < 3; i) //调用3次函数{hello_world();} } int main() {three_hellos();return 0; } 知…

Self-attention学习笔记(Self Attention、multi-head self attention)

李宏毅机器学习Transformer Self Attention学习笔记记录一下几个方面的内容 1、Self Attention解决了什么问题2、Self Attention 的实现方法以及网络结构Multi-head Self Attentionpositional encoding 3、Self Attention 方法的应用4、Self Attention 与CNN以及RNN对比 1、Se…

【Java开发岗面试】八股文—Java基础集合多线程

声明&#xff1a; 背景&#xff1a;本人为24届双非硕校招生&#xff0c;已经完整经历了一次秋招&#xff0c;拿到了三个offer。本专题旨在分享自己的一些Java开发岗面试经验&#xff08;主要是校招&#xff09;&#xff0c;包括我自己总结的八股文、算法、项目介绍、HR面和面试…

[Linux]Ubuntu noVNC使用

又到了逛大型程序员交友 网站的时间了&#xff0c;今天你准备好了吗。 今天要推荐的一个有趣的项目是noVNC setup好以后是这个样子的&#xff0c;可以在浏览器登陆vnc&#xff0c;不需要再安装一个vnc client. setup的过程比较简单&#xff0c;分为以下几步&#xff1a; 1. v…

关于时间与空间复杂度的学习

关于时间与空间复杂度的学习 算法时间复杂度定义标准算法度量单位渐近记号1、Θ&#xff08;big-theta&#xff09;2、O&#xff08;big-oh&#xff09;3、Ω&#xff08;big-omege&#xff09; 推导时间复杂度步骤与法则步骤法则 示例1.常数阶2、线性阶3、对数阶4、平方阶5、立…

数据结构 模拟实现LinkedList单向不循环链表

目录 一、链表的简单介绍 二、链表的接口 三、链表的方法实现 &#xff08;1&#xff09;display方法 &#xff08;2&#xff09;size得到单链表的长度方法 &#xff08;3&#xff09;addFirst头插方法 &#xff08;4&#xff09;addLast尾插方法 &#xff08;5&#xf…

SSM图书馆管理系统----计算机毕业设计

项目介绍 基于ssm的图书馆管理系统.主要功能包括&#xff1a;图书查询、图书管理、图书编辑、读者管理、图书的借阅与归还以及借还日志记录等。 用户分为两类&#xff1a;读者、图书馆管理员。图书馆管理员可以修改读者信息&#xff0c;修改书目信息&#xff0c;查看所有借还…