前言

CSS 有好几种写法. 它们最终出来的效果是一样的, 区别只是在你如何 "写" 和 "读" 或者说开发和维护.

这已经不是如何"实现"的问题了, 而是代码如何管理维护的问题.

参考

CSS Utility Classes and "Separation of Concerns" (Tailwind CSS 作者的文章, 一定要看)

CSS 架构系列 – OOCSS, BEMSMACSSACSS

Is BEM Framework the best one? Share alternatives!

RSCSS — Styling your CSS without losing your sanity .

BEM Is Terrible

CSS 进化论:从CSS,SASS,BEM,CSS Modules到Styled Components (英语原文)

重新构想原子化 CSS

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 – 管理的更多相关文章

  1. <转载> VUE项目中CSS管理

    vue的scoped 在vue项目中,当 .vue文件中 <style> 标签有 *scoped 属性时,它的 CSS 只作用于当前组件中的元素,很好的实现了样式私有化的目的. 使用sco ...

  2. web 页面内容优化管理与性能技巧

    回想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪存文件,里面包含的有视频或者图片.然而,随着移动开发的兴起,我 ...

  3. css的框架——global.css

    global.css,一般这个css文件是用于装全站主要框架css样式代码. “global”翻译为全局.全部.从翻译中大家也能理解global.css用于做什么.大站常常用于装全站公共的CSS样式选 ...

  4. css模块化思想(一)--------命名是个技术活

    引子: 女孩子都喜欢买衣服,而我也不例外,奈何钱包太瘦,买不起高大上的定制,只能买撞衫率极高的休闲衣,不过对于我来说,我还是开心的,毕竟买衣服买的不仅是衣服,更是一种心情.在web前端的世界里,css ...

  5. html和css命名标准以及常用的框架,我使用的是网易nec

    前端的工作很细,涉及的东西也很多,静态页面和js开发,调接口之类,有时还要自己设计.现在css管理使用less和sass,新东西起码要支持下,具体用与不用看公司的业务需求.前端人员之间的配合也很重要要 ...

  6. 知名网站内部资料:WEB页面内容优化管理与性能技巧

    回想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪 存文件,里面包含的有视频或者图片.然而,随着移动开发的兴起, ...

  7. web页面内容优化管理与性能技巧

    来源:GBin1.com 回 想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪 存文件,里面包含的有视频或者图片 ...

  8. css模块化思想(一)

    什么是css模块化思想?(what) 为了理解css模块化思想,我们首先了解下,什么是模块化,在百度百科上的解释是,在系统的结构中,模块是可组合.分解和更换的单元.模块化是一种 处理复杂系统分解成为更 ...

  9. CSS模块化思想-----命名是个技术活

    CSS模块化思想(一)--------命名是个技术活 引子: 女孩子都喜欢买衣服,而我也不例外,奈何钱包太瘦,买不起高大上的定制,只能买撞衫率极高的休闲衣,不过对于我来说,我还是开心的,毕竟买衣服买的 ...

  10. css 模块化

    什么是css模块化思想?(what) 为了理解css模块化思想,我们首先了解下,什么是模块化,在百度百科上的解释是,在系统的结构中,模块是可组合.分解和更换的单元.模块化是一种处理复杂系统分解成为更好 ...

随机推荐

  1. 解码 xsync 的 map 实现

    解码 xsync 的 map 实现 最近在寻找 Go 的并发 map 库的时候,翻到一个 github 宝藏库,xsync (https://github.com/puzpuzpuz/xsync) . ...

  2. JAVA私有构造函数---java笔记

    在Java中,构造函数是一种特殊的方法,它用于初始化新创建的对象.当我们创建一个类的实例时,构造函数会自动被调用. 构造函数可以有不同的访问修饰符,如public.protected.default( ...

  3. Linux环境 yum,apt-get,rpm,wget 区别

    Linux环境 yum,apt-get,rpm,wget 区别 一般来说linux系统基本上分两大类:cat /etc/issue查看linux系统版本RedHat系列:Redhat.Centos.F ...

  4. Android studio报错:Failed to allocate a 3213123 byte allocation with 31231 free bytes and 189MB ontil 0OM

    这个问题是运行内存超了 在AndroidManifest中加入 android:hardwareAccelerated="false"android:largeHeap= &quo ...

  5. 【微信小程序】 使用NPM包与VantWeapp

    小程序对npm的支持与限制 目前,小程序中已经支持使用npm安装第三方包,从而来提高小程序的开发效率. 但是,在小程序中使用npm包有如下3个限制: ① 不支持依赖于Node.js内置库的包② 不支持 ...

  6. 【MySQL】字符联合主键过长 Specified key was too long; max key length is 767 bytes

    MySQL版本: 这个情况在 8.0.28版本没有出现 报错如图 建表SQL: DROP TABLE IF EXISTS `pt_dict_common`; CREATE TABLE `pt_dict ...

  7. 武汉市委郭元强书记、盛阅春代市长会见白鲸开源CEO郭炜等嘉宾代表

    2024年6月14日,第二届软件创新发展大会在中国武汉举行.大会云集了来自全国的书数百位院士.专家.知名软件企业负责人,包括中国工程院院士倪光南.中国科学院院士陈十一.国家工业信息安全发展研究中心总工 ...

  8. 构建无服务器数仓(三 )EMR Serverless 操作要点、优化以及开放集成测试

    引言 在数据驱动的世界中,企业正在寻求可靠且高性能的解决方案来管理其不断增长的数据需求.本系列博客从一个重视数据安全和合规性的 B2C 金融科技客户的角度来讨论云上云下混合部署的情况下如何利用亚马逊云 ...

  9. 使用 Apache SeaTunnel 实现 Kafka Source 解析复杂Json 案例

    版本说明: SeaTunnel:apache-seatunnel-2.3.2-SNAPHOT 引擎说明: Flink:1.16.2 Zeta:官方自带 前言 近些时间,我们正好接手一个数据集成项目,数 ...

  10. vmware创建虚拟机

    1.vmware创建麒麟虚拟机 选择安装程序光盘映像文件,会最小化安装桌面版本,新的镜像可能识别不到,比如麒麟等. 麒麟系统类似于欧拉,欧拉类似于CentOS,所以我们选择CentOS 修改虚拟机名称 ...