『精』CSS 小技巧之BEM规范
『精』CSS 小技巧之BEM规范
文章目录
- 『精』CSS 小技巧之BEM规范
- 一、什么是BEM?
- 二、BEM要怎么用?
- 三、不用BEM会少个胳膊吗?💊
- 四、Sass与BEM的结合🎈
- 五、块与修饰符应放在一块👿
- 参考资料💘
- 推荐博文🍗
一、什么是BEM?
BEM风格规范指的是 Block、Element、Modifier 这三者的简称,这个规范将 CSS 拆分成块、元素、修饰符,根本作用是帮助开发者快速理解HTML与 CSS 之间的关系。那么通过使用 BEM 能获得到什么好处呢?我罗列了下面几点:
- 如果我们想制作一个组件的新样式,比如改个字体/背景色,可以很容易地看到有哪些样式项已经存在,只需要新增一个修饰符即可,甚至可能意识到一开始就不需要编写任何样式,有一个预先存在的修饰符可以满足我们的需求。
- 得益于 CSS 命名语义化的好处,我们能够快速了解其 HTML 结构分布,一个元素依赖哪一个元素,在产品变更时快速更改其样式,并完全确信您的更改不会产生副作用。
- 模块化的样式命名规则,能够最有效解决样式之间同名、继承、优先级等所带来的污染性问题,避免最后因为充斥着各种臃肿,而不敢触及修改遗留的各种未知样式,这其实给了开发人员一定的信心。
- 团队配合成本的降低,样式可读性的提高能够让成员之间能够快速复用已有的样式规则,而不需要再去编写一套样式。
在没有接触 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 最核心的写法就是用上 __
与 --
将样式命名进行区分。
三、不用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>
再来看看 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代码模板配置大全
相关文章:

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

vue3-12
需求是用户如果登录了,可以访问主页,如果没有登录,则不能访问主页,随后跳转到登录界面,让用户登录 实现思路,在用户登录之前做一个检查,如果登录了,则token是存在的,则放…...

操作系统期末复习
分段存储管理方式 某采用段式存储管理的系统为装入主存的一个作业建立了如下段表: 段号 段长 主存起始地址 0 660 210 1 140 3300 2 100 90 3 580 1237 4 960 1959 (1)计算该作业访问[0,432],[1&am…...

element el-table实现可进行横向拖拽滚动
【问题】表格横向太长,表格横向滚动条位于最底部,需将页面滚动至最底部才可左右拖动表格,用户体验感不好 【需求】基于elment的el-table组件生成的表格,使其可以横向拖拽滚动 【实现】灵感来源于这篇文章【Vue】表格可拖拽滚动&am…...

【兔子王赠书第14期】《YOLO目标检测》涵盖众多目标检测框架,附赠源代码和全书彩图!
文章目录 写在前面YOLO目标检测推荐图书本书特色内容简介作者简介 推荐理由粉丝福利写在后面 写在前面 小伙伴们好久不见吖,本期博主给大家推荐一本关于YOLO目标检测的图书,该书侧重目标检测的基础知识,包含丰富的实践内容,是目标…...
WPF 基础入门(样式)
3.1 一般样式 <Grid Margin"10"><TextBlock Text"Style test" Foreground"Red" FontSize"20"/> </Grid> 3.2内嵌样式 直接在控件上定义样式,如下所示: <Grid Margin"10">…...

Java ArrayList在遍历时删除元素
文章目录 1. Arrays.asList()获取到的ArrayList只能遍历,不能增加或删除元素2. java.util.ArrayList.SubList有实现add()、remove()方法3. 遍历集合时对元素重新赋值、对元素中的属性赋值、删除元素、新增元素3.1 普通for循环3.2 增强for循环3.3 forEach循环3.4 str…...

多模态大模型的前世今生
1 引言 前段时间 ChatGPT 进行了一轮重大更新:多模态上线,能说话,会看图!微软发了一篇长达 166 页的 GPT-4V 测评论文,一时间又带起了一阵多模态的热议,随后像是 LLaVA-1.5、CogVLM、MiniGPT-5 等研究工作…...

Android studio 花式按键
一、activity_main.xml代码: <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.a…...

使用spring boot实现异常的统一返回
在这个前后端分离的时代,一个 统一的数据格式非常重要。本次我们实现用spring boot实现一下返回给前端数据的统一格式,不再出现服务器500的错误。 新建一个spring boot项目,并导入knife4j的依赖。 写一个controller控制器,用来是…...

2023-12-11 LeetCode每日一题(最小体力消耗路径)
2023-12-11每日一题 一、题目编号 1631. 最小体力消耗路径二、题目链接 点击跳转到题目位置 三、题目描述 你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格…...
PID为1的僵尸进程的产生及清理
父进程PID为1的僵尸进程通常是由init系统(在Linux系统中通常是systemd)产生的。这种情况通常发生在以下几种情况: 子进程结束,但其父进程没有正确地调用wait()或waitpid()系统调用来获取子进程的退出状态。在这种情况下࿰…...

043、循环神经网络
之——RNN基础 杂谈 第一个对于序列模型的网络,RNN。 正文 1.潜变量自回归模型 潜变量总结过去的信息,再和当前信息一起结合出新的信息。 2.RNN 循环神经网络将观察作为x,与前层隐变量结合得到输出 其中Whh蕴含了整个模型的时序信息…...
node使用nodemonjs自动启动项目
安装 npm install -g nodemon使用方法 我这里用的是electron项目为例package.json配置 {"name": "my-electron-app","version": "1.0.0","description": "Hello World!","main": "main.js"…...

Ts自封装WebSocket心跳重连
WebSocket是一种在单个TCP连接上进行全双工通信的协议,允许客户端和服务器之间进行双向实时通信。 所谓心跳机制,就是在长时间不使用WebSocket连接的情况下,通过服务器与客户端之间按照一定时间间隔进行少量数据的通信来达到确认连接稳定的手…...

【unity学习笔记】捏人+眨眼效果+口型效果
一、vriod捏人 1.在vroidstudio软件中捏人 2.导出模型(.vrm) 二、vrid导入unity的插件 1.在Git上搜索、打开univrm。 2.找到release页面找到合适的插件版本。(VRM-0.116.0_0f6c) 3.将univrm导入到工程中(assets)。 三…...
动态规划 | 最长公共子序列问题
文章目录 最长公共子序列题目描述问题分析程序代码复杂度分析 最短编辑距离题目描述问题分析程序代码复杂度分析 编辑距离题目描述输入格式输出格式 问题分析程序代码 最长公共子序列 题目描述 原题链接 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共…...

RuntimeError: The NVIDIA driver on your system is too old.
【报错】使用 AutoDL 复现实验时遇到 RuntimeError: The NVIDIA driver on your system is too old (found version 11070). Please update your GPU driver by downloading and installing a new version from the URL: http://www.nvidia.com/Download/index.aspx Alternativ…...

Java开发过程中的幂等性问题
幂等性问题: 1. 有时我们在填写某些 form表单 时,保存按钮不小心快速点了两次,表中竟然产生了两条重复的数据,只是id不一样。 2. 我们在项目中为了解决 接口超时 问题,通常会引入了 重试机制 。第一次请求接口超时了…...

基于Docker的软件环境部署脚本,持续更新~
使用时CtrlF搜索你想要的环境,如果没有你想要的环境,可以评论留言,会尽力补充。 本文提供的部署脚本默认参数仅适合开发测试,请根据实际情况调节参数。 数据库 MySQL version: 3.9 services:mysql:image: mysql:8.0.35container…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解
进来是需要留言的,先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码,输入的<>当成字符串处理回显到页面中,看来只是把用户输…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...