CSS模块化方案PK:BEM/OOCSS/SMACSS/ITCSS、CSS Modules、CSS-in-JS
Author:zhoulujun Date:
JavaScript 社区中的 AMD、CMD、CommonJS、ES Modules 等类似,CSS 社区也诞生了相应的模块化解决方案:BEM、OOCSS、SMACSS、ITCSS,以及 CSS Modules 和 CSS-in-JS 等。
根据这些 CSS 模块化方案的特点,我简单的将它们分为了三大类:
CSS 命名方法论:通过人工的方式来约定命名规则。
CSS Modules:一个 CSS 文件就是一个独立的模块。
CSS-in-JS:在 JS 中写 CSS。
CSS 命名方法论
为了避免 CSS 选择器命名冲突的问题,以及更好的实现 CSS 模块化,CSS 社区在早期诞生了一些 CSS 命名方法论,如 BEM、OOCSS、SMACSS、ITCSS、SUITCSS、Atomic CSS 等。
它们几乎都有一个共同的特点——为选择器增加冗长的前缀或后缀,并试图通过人工的方式来生成全局唯一的命名。这无疑会增加了类命名的复杂度和维护成本,也让 HTML 标签显得臃肿。
BEM
BEM(Block Element Modifier)是一种典型的 CSS 命名方法论,由 Yandex 团队(鹅版百度)在 2009 年前提出,它的核心思想是 通过组件名的唯一性来保证选择器的唯一性,从而保证样式不会污染到组件外。
BEM 命名规约是 .block-name__element-name--modifier-name,即 .模块名__元素名--修饰器名 三个部分,用双下划线 __ 来明确区分模块名和元素名,用双横线 -- 来明确区分元素名和修饰器名。你也可以在保留 BEM 核心思想的前提下,自定义命名风格,如驼峰法、使用单下划线、使用单横线等。
在 BEM 中不建议使用子代选择器,因为每一个类名已经都是全局唯一的了,除非是 block 相互嵌套的场景。
优点:
命名规范:BEM 强调清晰的命名约定,使得样式层次结构和关系一目了然,便于团队协作和维护。
可重用性:由于 BEM 强调组件化设计,样式容易被复用,降低了重复代码的风险。
CSS 体系结构:BEM 通过命名规则和结构,强制开发者遵循一套标准的样式体系结构,减少了样式冲突的可能性。
缺点:
冗长的类名:BEM 的命名方式导致类名较长,可能影响代码的可读性,尤其是在复杂的组件结构中。
学习成本:需要团队中的所有成员都熟悉并遵循 BEM 的命名规范,否则容易产生不一致的问题。
灵活性不足:由于 BEM 的强规范性,在处理一些灵活或动态的样式需求时可能显得不够灵活。
OOCSS
OOCSS(Object-Oriented CSS)即面向对象的 CSS,它借鉴了 OOP(面向对象编程)的抽象思维,主张将元素的样式抽象成多个独立的小型样式类,来提高样式的灵活性和可重用性。
OOCSS由 Nicole Sullivan 在 2008 年提出!CSS Lint最初是由Nicholas C. Zakas和Nicole Sullivan编写的
Nicole Sullivan 可以说是Web技术布道者,前端性能优化和CSS专家 http://www.stubbornella.org
OOCSS 有两个基本原则:
独立的结构和样式:即不要将定位、尺寸等布局样式与字体、颜色等表现样式写在一个选择器中。
独立的容器和内容:即让对象的行为可预测,避免对位置的依赖,子元素即使离开了容器也应该能正确显示。
OOCSS 要求为这个容器创建更多的“原子类”,并且每个样式对应一个类,这样是为了后面可以重复使用这些组件的样式,避免重复写相同的样式
在 OOCSS 中,类名既要能传递对象的用途,也要有通用性,比如:
.mt-5 { margin-top: 5px; } .mt-10 { margin-right: 10px } .mt-15 { margin-bottom: 10px; }
其实可以改为
.mt-min { margin-top: 5px; } .mr-small { margin-right: 10px } .mb-medium { margin-bottom: 10px; }
类似的,还有颜色类。不要一blue red yellow 来直接命名,需要语义化,如:
--primary-color: #3a84ff; --success-color: #2dcb56; --warning-color: #ff9c01; --danger-color: #ea3636; --default-color: #63656e;
OOCSS适合做库的公用组件库封装,在大项目中使用,非常蛋疼
Tailwind CSS 不完全属于 OOCSS 方案
OOCSS(Object-Oriented CSS)的特点
OOCSS 强调将样式封装在独立的对象中,这些对象具有可复用性和可维护性。它鼓励开发者将样式分解成更小的、可组合的类,从而提高 CSS 的可扩展性。
Tailwind CSS 的特点
Tailwind CSS 是一种原子化 CSS 框架,它提供了一组高度可定制的、低级别的 CSS 类。这些类可以组合在一起,快速构建出复杂的 UI。
OOCSS缺点
1、样式与结构的耦合
问题:OOCSS 强调将结构(如布局)和外观(如颜色、字体)分离,但在实践中,这种分离可能会导致样式与 HTML 结构之间的耦合变得更加紧密。例如,为了实现某些布局效果,可能需要在 HTML 中增加额外的
div
或类名,这些标记仅仅是为了实现特定的样式需求。影响:这种耦合会导致 HTML 代码臃肿,降低了代码的语义性和可读性。
2. 类名污染
问题:OOCSS 的一个核心思想是通过复用类名来实现不同组件间的样式共享。这可能导致一个页面上出现大量相同的类名,尤其是在复杂的页面或组件中。
影响:大量的重复类名可能导致代码难以调试,尤其是在样式冲突时很难追踪问题的根源。此外,还可能导致 CSS 选择器的优先级管理变得复杂。
3. 代码膨胀
问题:OOCSS 强调可复用性,这意味着开发者在定义样式时,可能会倾向于创建大量的小的、可复用的类。虽然这有助于减少重复代码,但同时也可能导致样式表中出现大量的小类,增加 CSS 文件的体积。
影响:这不仅会导致样式表的加载时间变长,还可能会对样式表的可维护性产生负面影响,尤其是在大型项目中。
4. 学习曲线
问题:OOCSS 的理念与传统的 CSS 开发方式有所不同,开发者需要理解如何将结构与样式分离,以及如何创建可复用的对象和组件。
影响:对于没有使用过 OOCSS 的团队或个人来说,理解并有效地应用 OOCSS 需要一定的时间和学习成本。这可能会延长项目的初期开发时间。
5. 灵活性不足
问题:OOCSS 强调复用和模块化,但在某些情况下,这种复用可能会限制开发者的灵活性。特别是在需要创建独特的、非标准化的设计时,OOCSS 的规范可能会显得束缚。
影响:开发者可能不得不为了遵循 OOCSS 的原则而进行额外的工作,或在某些情况下,放弃 OOCSS 而采用更为灵活的解决方案。
6. 跨项目的适应性差
问题:OOCSS 在某些特定项目中可能效果很好,但当你试图将 OOCSS 的对象和组件移植到另一个项目时,可能会发现它们并不适用,尤其是在设计风格和布局大不相同时。
影响:跨项目复用时,可能需要对已有的 OOCSS 代码进行大量调整,削弱了其“可复用性”的优势。
SMACSS
SMACSS(Scalable and Modular Architecture for CSS)即可伸缩及模块化的 CSS 结构,由 Jonathan Snook 在 2011 年雅虎时提出。
SAMCSS 按照部件的功能特性,将其划分为五大类:
基础(Base)是为HTML元素定义默认样式,可以包含属性、伪类等选择器。
布局(Layout)会将页面分为几部分,可作为高级容器包含一个或多个模块,例如左右分栏、栅格系统等。
模块(Module)又名对象或块,是可重用的模块化部分,例如导航栏、产品列表等。
状态(State)描述的是任一模块或布局在特定状态下的外观,例如隐藏、激活等。
主题(Theme)也就是换肤,描述了页面的外观,它可修改前面四个类别的样式,例如链接颜色、布局方式等。
SMACSS 推荐使用前缀来区分不同部件:
基础规则是直接作用于元素的,因此不需要前缀。
布局的前缀是 l- 或 layout-,例如 .l-table、.layout-grid 等。
模块的前缀是 m- 或模块自身的命名,例如 .m-nav、.card、.field 等。
状态的前缀是 is-,例如 .is-active、.is-current 等。
主题的前缀是 theme-,例如 .theme-light、.theme-dark 等。
现在大部分的项目都是采用SMACSS方案,但是BEM有的缺点,他都有!
ITCSS
ITCSS(Inverted Triangle CSS,倒三角 CSS)是一套方便扩展和管理的 CSS 体系架构,它兼容 BEM、OOCSS、SMACSS 等 CSS 命名方法论。ITCSS 使用 分层 的思想来管理你的样式文件,类似服务端开发中的 MVC 分层设计。
ITCSS(Inverted Triangle CSS)是在2016年由阿里的Harry Roberts提出的——甲骨文、微软、亚马逊,2014年9月,以首席架构师的身份加入阿里巴巴速卖通(aliexpress),并于2017年3月晋升为CTO。
安利一下:郭东白的架构课
ITCSS 将 CSS 的样式规则划分成以下的几个层次:
Settings:项目使用的全局变量,比如颜色,字体大小等等。
Tools:项目使用的 mixins 和 functions。到 Tools 为止,不会生成具体的 CSS 代码。
Generic:最基本的设定,比如 reset.css、normalize.css 等。
Base:最基础的元素(elements),比如 img、p、link、list 等。
Objects:某种设计模式,比如水平居中,
Components:UI 组件,比如 button、switch、slider 等。
Trumps:用于辅助和微调的样式,只有这一层才可以使用
!important
。
ITCSS 的分层逻辑越往下就越具体,越局限在某个具体的场景。
根据 ITCSS 的思想,你可以这样组织你的 CSS 样式文件:
stylesheets/ ├── settings/ │ ├── colors.scss │ ├── z-layers.scss │ └── breakpoints.scss ├── tools/ │ ├── mixins.scss │ └── functions.scss ├── generic/ │ ├── box-sizing.scss │ └── normalize.scss ├── base/ │ ├── img.scss │ └── list.scss ├── objects/ │ ├── grid.scss │ └── media.scss ├── components/ │ ├── buttons.scss │ └── slider.scss ├── trumps/ │ ├── widths.scss │ └── gaps.scss └── index.scss
下面是几个基于 ITCSS 的模版项目,可供参考:
ITCSS缺点
配置复杂: ITCSS 的配置可能比较复杂,尤其是当项目规模较大或涉及多个团队协作时。这可能会增加维护成本,并引入潜在的错误。
命名复杂:为了遵循 ITCSS 的层次结构和命名规则,开发者可能需要创建复杂的类名或变量名,尤其是在处理多个相似的样式或组件时。复杂的命名规则可能会导致代码的可读性下降,特别是在跨团队协作或有新成员加入时,复杂的命名方式会让人感到困惑。
层次之间的依赖性使灵活性受限、复杂性增加: ITCSS 的严格层级结构在某些情况下可能会限制 CSS 的灵活性。如果需要进行一些非常特殊的样式调整,可能需要打破既定规则,从而增加代码的复杂性。
与第三方库的集成问题:在使用 CSS Modules 时,如何与第三方 UI 库或组件库集成可能会带来一些挑战。这些库通常会使用全局样式或特定的类名,而 CSS Modules 则会局部化样式,这可能导致样式冲突或无法正确应用第三方样式。
只要是靠人去保证代码质量总是不靠谱的,人的状态有起伏,但是机器没有,因此推荐用机器去解决这些问题。所以命名法从工程角度去看,主要依赖于人的主观能动性(总有不靠谱的时候)!
CSS Modules是解决上述问题的一个傻瓜式方案
CSS Modules
手写命名前缀后缀的方式让开发者苦不堪言,于是 CSS Modules 这种真正的模块化工具就诞生了。
上面提到的这些 CSS 命名方法论,虽然已经不适用于当今的自动化工作流和大前端环境,但是他们有其诞生的时代背景,也确实推动了 CSS 模块化的发展,其背后的设计思想同样值得我们学习,甚至有时候我们仍然能在某些场合下看到他们的影子。
CSS Modules 允许我们像 import 一个 JS Module 一样去 import 一个 CSS Module。每一个 CSS 文件都是一个独立的模块,每一个类名都是该模块所导出对象的一个属性。通过这种方式,便可在使用时明确指定所引用的 CSS 样式。并且,CSS Modules 在打包时会自动将 id 和 class 混淆成全局唯一的 hash 值,从而避免发生命名冲突问题。这样, 全局作用域污染、样式冲突、样式复用困难、 样式的可维护性、命名复杂性都解决了
CSS Modules 特性:
作用域:模块中的名称默认都属于本地作用域,定义在 :local 中的名称也属于本地作用域,定义在 :global 中的名称属于全局作用域,全局名称不会被编译成哈希字符串。
命名:对于本地类名称,CSS Modules 建议使用 camelCase 方式来命名,这样会使 JS 文件更干净,即 styles.className。 但是你仍然可以固执己见地使用 styles['class-name'],允许但不提倡。
组合:使用 composes 属性来继承另一个选择器的样式,这与 Sass 的 @extend 规则类似。
变量:使用 @value 来定义变量,不过需要安装 PostCSS 和 postcss-modules-values 插件。
这里仅罗列一些 CSS Modules 的核心特性,更具体的用法可以参考 官网 或 阮老师的《CSS Modules 用法教程》。
配合 CSS 预处理器使用
使用 CSS Modules 时,推荐配合 CSS 预处理器(Sass/Less/Stylus)一起使用。
CSS 预处理器提供了许多有用的功能,如嵌套、变量、mixins、functions 等,同时也让定义本地名称或全局名称变得容易。
CSS-in-JS
React 的出现,打破了以前“关注点分离”的网页开发原则,因其采用组件结构,而组件又强制要求将 HTML、CSS 和 JS 代码写在一起。表面上看是技术的倒退,实际上并不是。
React 是在 JS 中实现了对 HTML 和 CSS 的封装,赋予了 HTML 和 CSS 全新的“编程能力”。对于 HTML,衍生了 JSX 这种 JS 的语法扩展,你可以将其理解为 HTML-in-JS;对于 CSS,衍生出一系列的第三方库,用来加强在 JS 中操作 CSS 的能力,它们被称为 CSS-in-JS。
CSS-in-JS最初由Facebook的员工react核心成员Vjeux在2014年的NationJS会议上提出。
随着 React 的流行以及组件化开发模式的深入人心,这种"关注点混合"的新写法逐渐成为主流。
Any application that can be written in JavaScript, will eventually be written in JavaScript. —— Jeff Atwood
CSS-in-JS 库目前已有几十种实现,你可以在 CSS in JS Playground 上快速尝试不同的实现。下面列举一些流行的 CSS-in-JS 库:
styled-components:github.com/styled-comp… 33k(推荐)
emotion:github.com/emotion-js/… 13k
Radium:github.com/FormidableL… 7k(已不再维护)
Styled System:github.com/styled-syst… 7k
styled-jsx:github.com/vercel/styl… 6k
JSS:github.com/cssinjs/jss 6k
styled-components
styled-components 是目前最流行的 CSS-in-JS 库,在 React 中被广泛使用。
具体使用参看文档:https://styled-components.com/docs
CSS-in-JS缺点
CSS-in-JS 也有一些潜在的缺点,如增加了运行时开销、可能影响首次渲染性能、学习曲线较陡等。相比之下,CSS Modules 更接近传统 CSS 开发方式,性能开销较小,但功能相对简单。
总体来说:
对于需要高度动态样式和复杂主题管理的项目,CSS-in-JS 可能更有优势;
而对于追求更轻量级解决方案的项目,CSS Modules 可能是更好的选择。
选择CSS in JS之前,推荐读一下:
https://github.com/ascoders/weekly/blob/master/前沿技术/263.精读《我们为何弃用%20css-in-js》.md
https://hackernoon.com/stop-using-css-in-javascript-for-web-development-fa32fb873dcc
vue scope
vue scope 感觉像是 CSS Modules+CSS-in-JS 的异形!
在背后,Vue 会为该组件内所有的元素都加上一个全局唯一的属性选择器,形如 [data-v-5298c6bf],这样在组件内的 CSS 就只会作用于当前组件中的元素。
scope 简单的属性选择器性能是高于包含选择器。但是往往项目中有大量的嵌套属性选择器。
使用BEM 、ITCSS可以用@root 来规避嵌套。性能是优于scope方案的。还有就是scope样式穿透问题非烦人!
当然,个人还是推荐 CSS Modules
参考文章:
CSS 模块化方案探讨(BEM、OOCSS、CSS Modules、CSS-in-JS ...) https://juejin.cn/post/6947335144894103583
css 模块化相关 BEM/CSS Modules https://github.com/cisen/blog/issues/795
CSS Module用法总结 https://www.cnblogs.com/Ewarm/p/14150561.html
一些 CSS 管理方案的优缺点 https://ukn.me/yi-xie-css-guan-li-fang-an-de-you-que-dian.html
转载本站文章《CSS模块化方案PK:BEM、OOCSS、CSS Modules、CSS-in-JS》,
请注明出处:https://www.zhoulujun.cn/html/webfront/style/css3/2024_0807_9211.html
转载本站文章《CSS模块化方案PK:BEM/OOCSS/SMACSS/ITCSS、CSS Modules、CSS-in-JS》,
请注明出处:https://www.zhoulujun.cn/html/webfront/style/css3/2024_0808_9212.html