前言

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. 历代iPhone及Android手机的屏幕参数对比

    手机逻辑分辨率Point,也就是CSS像素,是进行网页适配的关键,以下是平时整理的一些备忘录数据,可以收藏. 屏幕清晰度分类 SD标清 HD高清(2倍屏) FHD全高清(3倍屏) QHD倍高清(4倍屏 ...

  2. AT_arc041_b 题解

    洛谷链接&Atcoder 链接 本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读. 题目简述 给定一个 \(N \times M\) 的矩阵,此矩阵的每一个元素都向上.下.左.右 ...

  3. JavaScript小面试~href和src的区别

    href:中文名称叫超文本引用 src:中文叫资源 先要知道它们两个的区别,我们首先要看哪些元素在使用这些属性. href:a,link src:img,style,input,script,ifra ...

  4. 【MySQL】编写随机密码生成脚本

    数据需求: 密码规则是 12位 数字 + 字母 混合后MD5加密 然后导出一个表格或者记录文件,文件没明确要求 实现过程: 1.MD5加密函数使用 SET @txt = '123456'; SELEC ...

  5. 【Scala】08 模式匹配 Match Case

    由Scala封装的一套match case处理,功能比原Java的更为强大 package cn import scala.collection.immutable.IndexedSeqDefault ...

  6. 【Dos-BatchPrograming】04

    --1.PING 主机联通性检测 Microsoft Windows [版本 10.0.19041.746] (c) 2020 Microsoft Corporation. 保留所有权利. C:\Us ...

  7. 【DataBase】MySQL 31 游标

    游标 Cursor 游标是用来存储查询的结果集的数据类型,也称为是光标 在存储过程和函数中可以使用光标对结果集进行循环的处理 光标的使用包括1.声明,2.开启,3.关闭,4.Fetch 游标仅用于存储 ...

  8. 计算机论文中的SD SE是什么 ?

    Standard Deviation (SD) and Standard Error (SE): 标准差和标准误差:在统计学和数据分析中常用来描述数据的分布和估计值的精确性.SD 表示标准差,SE 表 ...

  9. 【转载】 pytorch reproducibility —— pytorch代码的可复现性

    原文地址: https://www.jianshu.com/p/96767683beb6 作者:kelseyh来源:简书 ======================================= ...

  10. 一个域名可以对应多个IP吗,一个IP可以对应多个域名吗?

    本文谈两个问题:一个域名可以对应多个IP吗,一个IP可以对应多个域名吗? 问题1:一个IP可以对应多个域名吗? 因为域名都是由各个域名供应商提供的,我们可以在不同的域名供应商那里买不同的域名,然后把这 ...