CSS – 管理
前言
CSS 有好几种写法. 它们最终出来的效果是一样的, 区别只是在你如何 "写" 和 "读" 或者说开发和维护.
这已经不是如何"实现"的问题了, 而是代码如何管理维护的问题.
参考
CSS Utility Classes and "Separation of Concerns" (Tailwind CSS 作者的文章, 一定要看)
CSS 架构系列 – OOCSS, BEM, SMACSS, ACSS
Is BEM Framework the best one? Share alternatives!
RSCSS — Styling your CSS without losing your sanity .
CSS 进化论:从CSS,SASS,BEM,CSS Modules到Styled Components (英语原文)
Youtube – 7 ways to deal with CSS
CSS 模块化方案探讨(BEM、OOCSS、CSS Modules、CSS-in-JS ...)
React拾遗:从10种现在流行的 CSS 解决方案谈谈我的最爱 (上), (中), (下)
Selector 流派
职责
HTML 只负责内容结构, 不涉及任何 "Styling" 这个是 selector 流派的重点.
所有 Styling 交给 CSS 负责.
它们之间的 connect 方式就是通过 selector.
Selector 方式与 class 命名
selector 要好维护, 就必须避开一些潜在的风险.
1. selector 要稳定.
比如我想给一个 icon styling. 我用 tag selector 的话, 可能是 <i> 也可能是 <svg> (fontawesome 用 <i>, 其它可能用 svg)
这样就不太稳定, 改成 class name .icon 就稳定了. 所以一般上大家都会建议 selector 用 class name, 不要用 tag name.
但这也不是绝对的, 关键就是你认为它是否稳定.
2. class name 撞名字
selector class 是全局的, 这意味着一不小心就会撞名字了.
比如
.section-1 .title
.section-2 .title
title 就是一个重复的 class name. 但它们的样式不一定是相同的. 因为当我们在命名的时候, 我们的潜意识, 是有作用域概念的.
BEM
BEM 就是通过 namespace 的命名方式, 解决 class name 撞名字的问题的.
其原理就是把名字取长一点...比如 block__element--modifier
.section-1 .section-1__title
.section-2 .section-2__title
CSS Modules
另一个方法是通过 CSS Modules, 比如 Angular omponent styles 或者 Asp.net Core – CSS Isolation
它们的原理是通过 pre-compile 动态帮你添加 namespace. 方式和 BEM 差不多, 只是 BEM 是 manual 的, 这个是 auto 的. 管理上差很大.
Descendant / Child selector (RSCSS)
.section-1 > title
.section-2 > title
只要确保 root selector 不要撞名字, 通过 descendant selector 是可以确保后续不会撞的. 注意: 如果有嵌套的话, 最好使用 > child selector
不然还是有可能会撞名字的.
BEM vs RSCSS BEM 的缺点是 class name 长, descendant 的缺点是并不能 100% 做到保护, child 的缺点是没有 descendant 那么干净.

左图是 BEM 的 HTML 页面, class name 很长, 很丑
右图是 RSCSS child selector 的画面, 就是多了很多 > 箭头, 而且层次结构需要完全与 HTML 一致 (耦合度比 BEM 大)
疑惑
问: class="btn-blue" 是一个合格的 class name 吗?
答: 不是, blue 是样式.
缺点和局限
selector 流派最大的问题就是 Styling 的复用. 按照它的标准, 一个 element 只会有一个 class name 来表示.
所有 styling 也只能写到这个 class 上面, 那怎么能复用呢?
.page-title-section
.call-to-action-section
比如上面 2 个 class 是不同的东西. 但是它们都是 section
想抽象 section style 有几个做法.
1. .page-title-section, .call-action-section 用"或者" selector
2. 添加多一个 class 到 HTML
class="page-title-section section" <-- 像这样.
但这样你就会觉得怪怪的了. 因为 class 的作用应该只是为了能 selector 到它. 那为什么要搞 2 个呢?
其实是为了 styling. 而我们说过 HTML 不应该被 Styling 影响.
3. 用 Sass 的 @extend 或 @include
方法 1 和 3 是比较正确的方式, 2 有一点点偏向 Atom 流派了.
伪命题
有人说, HTML 和 CSS 不要耦合, 要分开.
1. 当你修改 HTML 的时候不要影响到 CSS
2. HTML 可以独立复用, CSS 也可以独立复用.
我想说的是, 不要去搞这些东西. 绝大部分的时候 HTML, CSS 甚至 JS 是密不可分的.
这也是为什么 React, Tailwind CSS 最终会把 3 剑客写成一团.
另一个话题是, 写成一团好不好, 看上去确实乱, 但是也没有乱到不能管理.
像 Angular, 它不直接在 HTML 写 TS, 但它需要搞指令来完成那些 TS 做的事儿. 比如 *ngIf *ngFor
这算是一个 trade-off. 尽可能不要那么乱, 但也限制了一些灵活.
Atom 流派
从上面的开发过程, 我们可以看到绝大部分的情况. CSS 的职责是作为 HTML 的 makeup.
CSS 的 selector 就是一个为了 connect 而诞生的东西.
如果我们直接把 CSS 写进去 HTML 那么就不需要这些 connect 了.
Inline CSS
inline CSS 是一个解决方案, 它几乎就是把 CSS 的 Style "搬" 到了 HTML 而已.
这个价值不够大.
Atom Class
把每一个小小的 Styling 变成一个 class
class="py-3" 相等于 padding-block: var(--spacing-3)
这个做法比 inline 好了不少.
有一点点像是重新定义了 CSS 语法.
它的特点是 shorthand key/value,
padding-block 很长, 写成 py 就好.
var(--spacing-3) 很长, 改成 -3 就好了.
优缺点, 有点是写的很爽. 短嘛.
缺点是, 读的时候有点累, 短嘛.
经过一轮升华, 价值大了一些
Tree Shaking
CSS 一直写就会越来越大, 如果把它变成 Atom Class 那么你增加的就不是 CSS 而只是 HTML 上的 class name 而已了.
通过 pre-compile 技术可以把没有用到的 class 排除. 这样就可以尽可能的少 Style 了.
价值多提升了一点点
Pre-compile = whatever
TypeSciprt 是典型的 pre-compile 神器. 任何可以 pre-compile 的东西都可以重新定义一个写法.
这就好像高级语言最终会生成低级语言一样. 高级语言的好处就是开发快, 维护方便.
Tailwind CSS 也是类似的东西. 代价就是学习成本和局限性而已.
对 CSS Utility Classes and "Separation of Concerns" 的整理
这篇文章写了很多重点. 这里做一个整理
Phase 1: "Semantic" CSS
这个是 selector 流派.
开发步骤是
1. 写 HTML, 定义 class name 依据内容 (不包含 styling)
2. 写 CSS, selector + styling
CSS 的结构会和 HTML 高度一致. selector 利用 descendant / child selector 方式避免撞名字.
Phase 2: Decoupling styles from structure
Phase 1 的问题在于严重依赖结构, 以至于 HTML 稍微改动一下, CSS 也必须修改.
我个人是觉得还好. 就一起改呗. 但是有些人认为不太好. 于是他加入了 BEM
BEM 会把 CSS 结构 "打平". 不再有嵌套, 也不用 descendant / child selector. 改用长长的 class name 做 select.
由于强制结构只有一层, 所以 HTML 和 CSS 的结构偶尔就没有了.
Dealing with similar components
上面的方式还不错了. 但是遇到类似的组件就完了.
作者提了 3 个方案
1. duplicate style (这个是开玩笑的)
2. @extend, @include
3. 抽象 class 这个是大部分 library 封装的方式 (可以参考 Swiper.js 的封装和调用)
到这里就是一个关键的转捩点了. 之前都是先有 HTML 然后 CSS makeup style (HTML 在前, 它不需要 "认识" CSS, 相反 CSS 在后需要 "认识" HTML)
但现在 CSS Style 要被复用了. 对于第二个 HTML 来说, CSS 反而在前, HTML 在后了.
下面这段讲出了重点

"Separation of concerns" is a straw man
HTML 和 CSS 的关系是很密切的. 强行分开它们是不正确的思路.
反而要理解它们的依赖关系.
1. CSS that depends on HTML
这个就是上面提到的, 先写 HTML 然后 CSS makeup HTML
2. HTML that depends on CSS
这个就是上面提到的, CSS 复用, 先 CSS 然后 HTML 配合.

不同的人会选择不同的路线.
Phase 3: Content-agnostic CSS components
作者倾向于第 2 条路, 让 CSS 复用.
后来他意识到, 组件越完整越难被复用.

于是就加入了 atom css 的概念. 后续的我就不写了, 大致上就是加入了更多其它 "价值" 推出了 Tailwind CSS.
对 Youtube – 7 ways to deal with CSS 的整理
同时参考了: CSS 模块化方案探讨(BEM、OOCSS、CSS Modules、CSS-in-JS ...)
1. pure css (selector 流派), 问题撞名字
2. BEM 引入 namespace 名字就不撞了.
3. CSS Modules 用 pre-compile 自动做 namespace
4. CSS in JS 用 JS 来写 CSS. React 用 JS 写 HTML 后得到了启发, 也可以用 JS 去写 CSS 这样甚至取代了 Sass 的作用.
5. styled-components 是 CSS in JS 的实现库.
6. Tailwind CSS atom CSS 的框架. 同时它也有取代 Sass 部分能力的能力.
总结
方案真的是好多啊. 我个人的经验是这样的.
1. Angular
Angular 自带 Component styles, 所以不需要搞 BEM, CSS Modules 那套
它是用 Sass 的, 所以也不搞 CSS in JS 那套.
至于你要不要用 Tailwind CSS 这个倒是可以考虑的.
2. React / Vue
据说 CSS in JS 就有十几个 library 在做. 这就是生态繁荣吧. php 框架也是有几十个.
如果喜欢做选择, 那么可以都尝试看看
3. ASP.NET Core 传统 way
Sass + BEM 或者 only Tailwind CSS 也是不错的做法.
我目前的做法 (ASP.NET Core 项目):
我目前的做法是 Phase 1: "Semantic" CSS
步骤是这样的.
1. 写 HTML
2. 写 CSS class (CSS 结构和 HTML 完全一致, 只是添加了 class 命名)
3. class 命名没有用 BEM, 用的是 RSCSS Descendant / Child selector 的方式, 加一点自己的规范, 防止撞名的同时尽量确保 class name 短 (我不能接受 class name 长长...)
4. 遇到复用的 Styling 用 "或者" selector 和 @extend @include 就解决.
5. 遇到组件复用的话, 会把 HTML, CSS, JS 做成组件. 类似 Swiper library 加上 Razor 的 View Component.
CSS – 管理的更多相关文章
- <转载> VUE项目中CSS管理
vue的scoped 在vue项目中,当 .vue文件中 <style> 标签有 *scoped 属性时,它的 CSS 只作用于当前组件中的元素,很好的实现了样式私有化的目的. 使用sco ...
- web 页面内容优化管理与性能技巧
回想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪存文件,里面包含的有视频或者图片.然而,随着移动开发的兴起,我 ...
- css的框架——global.css
global.css,一般这个css文件是用于装全站主要框架css样式代码. “global”翻译为全局.全部.从翻译中大家也能理解global.css用于做什么.大站常常用于装全站公共的CSS样式选 ...
- css模块化思想(一)--------命名是个技术活
引子: 女孩子都喜欢买衣服,而我也不例外,奈何钱包太瘦,买不起高大上的定制,只能买撞衫率极高的休闲衣,不过对于我来说,我还是开心的,毕竟买衣服买的不仅是衣服,更是一种心情.在web前端的世界里,css ...
- html和css命名标准以及常用的框架,我使用的是网易nec
前端的工作很细,涉及的东西也很多,静态页面和js开发,调接口之类,有时还要自己设计.现在css管理使用less和sass,新东西起码要支持下,具体用与不用看公司的业务需求.前端人员之间的配合也很重要要 ...
- 知名网站内部资料:WEB页面内容优化管理与性能技巧
回想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪 存文件,里面包含的有视频或者图片.然而,随着移动开发的兴起, ...
- web页面内容优化管理与性能技巧
来源:GBin1.com 回 想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪 存文件,里面包含的有视频或者图片 ...
- css模块化思想(一)
什么是css模块化思想?(what) 为了理解css模块化思想,我们首先了解下,什么是模块化,在百度百科上的解释是,在系统的结构中,模块是可组合.分解和更换的单元.模块化是一种 处理复杂系统分解成为更 ...
- CSS模块化思想-----命名是个技术活
CSS模块化思想(一)--------命名是个技术活 引子: 女孩子都喜欢买衣服,而我也不例外,奈何钱包太瘦,买不起高大上的定制,只能买撞衫率极高的休闲衣,不过对于我来说,我还是开心的,毕竟买衣服买的 ...
- css 模块化
什么是css模块化思想?(what) 为了理解css模块化思想,我们首先了解下,什么是模块化,在百度百科上的解释是,在系统的结构中,模块是可组合.分解和更换的单元.模块化是一种处理复杂系统分解成为更好 ...
随机推荐
- Linux如何安装PHPMyAdmin
1,我们要以root帐号登入 . 2,PHP支持模块安装.在CentOS操作系统安装完毕后,其实PHP支持模块并没有安装上去,如果想使用PhpMyAdmin,首先需要安装PHP支持模块,我们需要两个P ...
- tp5生命周期
https://www.kancloud.cn/manual/thinkphp5/118011 1.入口文件 用户发起的请求都会经过应用的入口文件,通常是 public/index.php文件.当然, ...
- oeasy 教您玩转linux 之 010209 装酷利器 hollywood
我们来回顾一下 上一部分我们都讲了什么? 屏幕故障风格的软件包bb 可以设置音频 这次装一个酷 下个hollywood软件包 apt show hollywood apt search hollywo ...
- Day 4 - 搜索进阶与模拟
启发式搜索 下面将简要介绍启发式搜索及其用法. 定义 启发式搜索(英文:\(\text{heuristic search}\))是一种在普通搜索算法的基础上引入了启发式函数的搜索算法. 启发式函数的作 ...
- Python shortuuid生成库学习小结
shortuuid生成库学习小结 by:授客 QQ:1033553122 实践环境 win10 Python 3.5.4 shortuuid-1.0.1-py3-none-any.whl 下载地址: ...
- BeanUtils.copyProperties无法复制list对象,替换为lambda表达式
List<Setmeal> setmeals = setmealMapper.selectList(queryWrapper); List<SetmealVO>vo=new A ...
- OpenStack 基本命令
keystone source /etc/keystone/admin-openrc.sh #登录 openstack user create --password ps1234 --email hq ...
- Python和RPA网页自动化-让select标签下拉框选择指定文本的方法
以影刀商城(https://shop.yingdao.com/webOperations/index)为例: 该下拉框有<select>标签.分别使用Python和RPA网页自动化让下拉框 ...
- 【SpringBoot】11 Web开发 Part2 模板引擎
开发回顾: JavaWeb开发使用JSP技术,所有的页面文件必须是JSP,才能接受数据处理 JSP的好处是,数据交互方便,有JSTL补充 SpringBoot的区别: 我们最终的项目是一个jar包 内 ...
- 大语言模型内部运行原理 | LLM | 词向量 | Transformer | 注意力机制 | 前馈网络 | 反向传播
https://www.understandingai.org/p/large-language-models-explained-with https://arxiv.org/abs/1905.05 ...