Erlo

CSS设计模式

2025-01-10 00:29:42 发布   32 浏览  
页面报错/反馈
收藏 点赞

OOCSS

  • OO(“Object Oriented”):面向对象。

  • OOCSS:Object Oriented css(面向对象css)的缩写,是一种用最简单的方式编写的CSS代码,从而使代码 重用性,可维护性和可扩展性更好的书写方法。

OOCSS 解决的问题

很多开发者在编写 CSS 时,经常会遇到以下问题:

  • 样式重复: 同样的样式在不同的地方重复定义,导致代码冗余。

  • 代码难以维护: 随着项目规模的扩大,CSS 代码变得越来越复杂,难以维护。

  • 样式冲突: 不同组件之间的样式容易互相干扰,导致样式冲突。

但 OOCSS 则将CSS代码模块化,大量减少了样式重复和冲突的问题,且做到了修改一个模块可以同时修改多个组件,增加了可维护性。

OOCSS 总体思想

OOCSS 的核心思想是 通过将 CSS 代码模块化,提高代码的复用性和可维护性。且各个模块之间不相互影响,模块也可以随时随地使用。

所以 OOCSS 的代码风格就可以浓缩为:

  • 零件多而散: 一个DOM元素上可能挂了许多个类名才能拼接出一个效果。

  • 不使用继承选择符: 既然要“随时随地用”,当然不能受到“继承”关系的制约,所以OOCSS几乎不适用继承选择符。

学习 OOCSS 需要了解其两大基本原则

  • 分离结构与外观 / Separate structure and skin

  • 分离容器与内容 / Separate container and content

分离结构与外观

分离结构与外观的含义就是:一个组件的结构(如宽高、边框、边距等)和外观(如背景、颜色等)应该分开定义在不同的 CSS 类当中。

这样做的好处就是,当你想给组件换个“皮肤”,就不会再受组件结构相关CSS的影响。你只需把控制外观的类更换一下即可实现换肤

这样一来,你能构成的组件样式就有结构样式数 × 外观样式数 个,感觉是不是比一个个写好多了?这就是增加了代码复用性。

分离容器与内容

分离容器和内容实际上就是要求所有样式尽可能脱离它的内容,不管一开始它是为谁而服务的。

比如一开始专门为一个卡片.card设计了一个按钮,命名为.card-btn。但是也许这个按钮其实非常通用,卡片的前缀反而局限了这个按钮的用途,此时就是“容器”与“内容”深度绑定了。

另外一个更极端的案例,那就是使用继承****选择符了,例如.card .btn。这不仅在命名上局限了按钮的用途,甚至局限了其在DOM结构中的使用。

所以若要遵守分离容器与内容,应当做到:

  • 不使用继承选择符(形如.container li{...}的结构),以达到子元素即使离开了容器也应该能正确显示的效果。

  • 尽量不给样式限定用途 以让样式具有可复用性。

BEM

BEM(Block Element Modifier)是一种常用的CSS命名约定,用于帮助开发者更好地组织和管理CSS代码,其本质就是进阶版的OOCSS。

BEM将页面的视图分为块(Block)、元素(Element)、修饰符(Modifier),如何理解它们之间的关系呢? 如下图所示:

  1. 块(Block):它代表功能独立的整体,是一系列结构、表现和行为的封装。块的类名应该使用简短而具有描述性的名字(如:.tabs、.card)

  2. 元素(Element):顾名思义,块内部的内容就是元素,它代表块中的组成部分。元素的类名由块名和元素名以双下划线(__)进行连接(例如:.card__title、.tabs__item)。

  3. 修饰符(Modifier):如上图所示第三个元素,它拥有个性化样式,我们需要单独为它添加样式。通过添加修饰符类,我们可以轻松修改块或元素的外观、状态。修饰符的类名由块或元素名后面加上连字符(--),然后加上修饰符名称(例如:.card--highlighted、.button--disabled)

这是一段文本内容。

这是一段文本内容。

这是一段文本内容。

SMACSS

SMACSS(Scalable and Modular Architecture for CSS)是一种CSS设计模式,旨在帮助前端开发工程师更好地组织和管理大型项目中的CSS代码。

SMACSS的核心思想是将项目样式代码划分为不同的模块,并根据其功能和作用进行分类。这种分类使得样式的结构更清晰,对于新的需求或变化的需求可以更容易地进行修改。

下面是SMACSS的五个主要原则:

  1. 基础(Base):基础样式主要是对浏览器默认样式的重置。

  2. 布局(Layout):布局样式定义了页面的整体结构和布局,如头部、侧边栏、页脚等。

  3. 模块(Module):模块样式定义了可重复使用的独立组件,如导航栏、卡片、按钮等。每个模块应该具有自己的封装和独立性,以便于在不同的页面上进行复用。

  4. 状态(State):状态样式定义了元素在特定状态下的样式,如鼠标悬停、选中、禁用等。状态样式可以通过添加类名或伪类来应用,并且应该与模块样式分开。

  5. 主题(Theme):主题样式定义了页面的整体风格和视觉差异,如颜色、字体等。主题样式可以根据具体的项目需求进行定制。

注意:SMACSS设计模式核心思想是分类。至于在实际工作中CSS代码是否完全按照这5个原则进行划分则无关紧要,比如说项目中没有主题要求,则完全可以不考虑主题层级。

ACSS

ACSS 的概念

ACSS 是 Atomic CSS 的简写,它是 Thierry Koblenz 在 2013 年 10 月的文章 Challenging CSS Best Practices 中创造的。

首先,让我们为 原子化 CSS (Atomic CSS) 给出适当的定义:

John Polacek 在文章 Let’s Define Exactly What Atomic CSS is 中写道:

Atomic CSS is the approach to CSS architecture that favors small, single-purpose classes with names based on visual function.

译文:原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class,并且会以视觉效果进行命名。

除了叫 ACSS,你还可以称它为函数式 CSS,或者 CSS 实用工具。

CSS 是一个不强调逻辑,而更侧重表现的一门所见即所得的语言,当样式写多了,你就会发现常用样式的来来去去也就那几个,无非就是调整一下他们的排列组合。每次写这些重复的样式代码我就感觉自己是在重复造轮子,自然而然就产生了想要缩写的需求,而 ACSS 做的一些事情很平常,无非就是把 CSS 属性写成一个独立的类名。

ACSS 和 CSS-in-JS 为什么会火

前面我们明白了 ACSS 的概念,所以接下来我要讲下 CSS-in-JS 的概念,然后才好解释为什么它们会火。

CSS-in-JS 是很重要的概念,本来打算写篇文章介绍的,题目都取好了 「CSS 架构之 CSS-in-JS」,整理资料发现阮一峰老师写过了,那我就直接拿过来吧 阮一峰——CSS in JS 简介,但是阮老师并没有给出流行 CSS 的解决方案,现在都 21 年了,我们知道目前流行着好几种解决方案,方案各有利弊,我们需要一篇文章来通透的理解它们,于是 @FateRiddle 同学的 React拾遗:从10种现在流行的 CSS 解决方案谈谈我的最爱 (上) 这篇文章出现了。

你可以先不看上面的文章链接,我来给你梳理下:

很久以前,前端项目比较小,HTML、CSS、JS 都耦合在一起,后来随着项目越来越大,为了便于维护,代码不允许在耦合,要求各个技术只负责自己的领域。

在后来,伴随着 React 出现,前端组织代码的方式变了,组件成为组织代码主流方法,而组件的核心原则就是代码完全不依赖外部,表现在 React 中就是 HTML、CSS、JS 强强耦合,这样就避免了影响其他组件,对于 CSS 我们也写在了 JS 中,这就要 CSS in JS,其实就是写行内样式。

但行内样式不支持伪类、媒体查询,于是出现了 React-JSS 这种库,对行内样式进行扩展;有人又不能忍受 React-JSS 这种样式驼峰的写法;出现了 styled-components,遵循 CSS 写法规范的库;有人比较喜欢不耦合的写法,于是 Css Module 出现了;还有人觉得 Vue 的解决办法比较优雅,然后就出现了 styled-jsx。

我来总结下:

CSS-in-JS 本质就是行内样式,之所以会火就是因为组件化时代的到来。

看明白 CSS in JS 火的原理,你肯定猜到 ACSS 会火的原因——那就是组件化时代的到来,你甚至可以理解为 ACSS 就是 CSS 架构下得 CSS 组件化。

在没有组件化的传统网页开发时代,如果你通过 ACSS 来确定样式,例如下面代码的形式,合作的小伙伴肯定以为你疯了:


因为 button 的复用率很高,你项目到处充斥着这种 button,一旦 button 要修改某些样式,你可去哭娘去吧,这哪有直接给个 .btn 类名方便,要修改直接改类名就行了,例如下面:


但是在组件化时代就不一样了,例如使用 React 封装一个 Button:

const Button = ({ children, color }) => (    )

使用如下:


如果样式有修改,我只要插拔 ACSS 就行了,而且对比使用 .btn 实现,样式的重用性会极大提高,理解也很容易。

这下你明白了吗,要说 ACSS 和 CSS-in-JS 为什么会火,就是因为***组件化***。

ACSS 优劣

使用 ACSS 的好处:

  • 你的 CSS 停止增长。使用传统方法,每次添加新功能时,您的 CSS 文件都会变大。使用实用程序,一切都是可重用的,因此您很少需要编写新的 CSS,一套样式全局通用。

  • 你不是在浪费精力发明类名。不再添加愚蠢的类名,例如 sidebar-inner-wrapper 只是为了能够设置样式,也不再为真正只是一个 flex 容器的东西的完美抽象名称而苦恼。

  • 灵活,易读。CSS 是全球性的,当你做出改变时,你永远不知道你破坏了什么。HTML 中的类是本地的,因此您可以 插拔式改变样式 而不必担心其他问题,CSS 样式很多缩写更加符合大脑的记忆。

  • 永远不用担心命名冲突,永远不用担心样式覆盖

使用 ACSS 劣处:

  • 毫无疑问,ACSS 会增加HTML 的体积,但是借助 Gzip 这个就不是大问题。

  • 熟悉命名 ACSS 命名会有一定成本。

ACSS 劣处是非常小的,而好处有非常大,没有理由在项目中不适用,强烈建议你每个前端项目都是用 ACSS。

如何选择 ACSS 库

市面上有不少成熟的 CSS 框架,如 Tailwind CSSWindi CSS 以及 Tachyons 等。

同时有些 UI 库也会附带一些 CSS 工具类作为框架的补充,如 BootstrapChakra UI

甚至还有一些人根据项目总结出来自己的 ACSS,例如 atom.cssSACSS: Static Atomic CSS 等。

ACSS 库大致就分为这三类了。

把它们整合到我们的项目,那我们选择的标准是什么呢?

  1. 按需生成,比如我们使用 class="m-1" 来设置 margin,那么 m-x,x 到底是多大呢,x 但不管 x 是多大,当增加 x 的时候,margin 不同方向,比如 mt 代表 margin-topmb 代表 margin-bottom 等,也得增加,如果加上 :hover:focus 这样的伪类时,体积还会得更变大,原子类太多了,应该提供按需生成只加载我们用过的。

  2. 动态化,原子类不应该是完全静态化的,比如我要使用 class="m-100" ,我应该可以是直接使用,而不是设置完之后,发现样式没生效,然后通过框架的配置文件,去增加对 m-100 的支持,原子类要把可插拔做到极致。

除了上面两个是非常重要的标准,我认为 自动值推导属性化模式 也是提升了开发体验要考虑的部分。

我们来看看我们最终会选择哪个 ACSS 库,首先原子 CSS 一定要纯净,所以 UI 框架附带的 ACSS 就不能采用了,根据项目总结的 ACSS,它的原子 CSS 太过静态,不能随想随用,不符合原子类不应该是完全静态化的标准,Tailwind CSS 本来是没有按需生成的,后来增加了,但是 Windi CSS 速度更快还兼容 Tailwind CSS,所以我们很自然就必须必的选择了 Windi CSS

总结

我们先通过举例子,了解了 ACSS 的使用,然后介绍了 ACSS 的概念,通过对比 CSS-in-JS 来剖析 ACSS 借助前端组件化浪潮开始起飞的过程,最后如何在项目中选择自己的 ACSS 库,我们通过一些硬性标准,分析了三类 ACSS 库,帮你选择了 Windi CSS

ITCSS

ITCSS(Inverted Triangle CSS)设计模式的起源可以追溯到2013年,由Harry Roberts提出。Harry Roberts是一位著名的前端开发专家和顾问,他在实践中发现,许多项目在处理CSS时都存在类似的问题:样式表无序、样式冲突、复杂度高、维护困难等。

为了解决这些问题,Harry Roberts提出了ITCSS设计模式,其灵感来自于CSS的层叠特性。通过将样式表按照特定的层次结构组织起来,使得样式规则更具层次性和可维护性。那他具体是如何处理的呢?

ITCSS的核心思想是分层,目前普遍意义上把项目划分成了七层,如下:

1、Settings(设置):在这个层次中,我们定义项目中的变量、配置和全局选项等。这些设置可以是颜色、字体、间距等通用的样式变量,供其他层次使用。

2、Tools(工具):在这个层次中,我们定义一些辅助函数、混合器(mixins)或者其他工具类。例如 SCSS 中的 @mixin 、@function。

3、Generic(通用):在这个层次中,主要是重置浏览器默认样式(normalize.css),或者标准化样式(reset.css)。

4、Elements(元素):在这个层次中,主要是根据自身项目需要 对一些元素进行定制化的设置,例如重新覆盖A 标签默认样式等。

5、Objects(对象):在这个层次中,我们定义可复用的、独立的样式模块。相当于SMACSS中的Layout。

6、Components(组件):在这个层次中,我们定义特定的页面组件,和Element UI这种组件库单独为每个组件定义样式相似。

7、Trumps 层: 根据实际需要设置 important! 的地方。

但这七层也不都是必须的,而是根据实际的项目需要去划分的。下面我们以Element-plus为例,来看下在实际的项目中,ITCSS设计模式是如何运用的。

ITCSS 要解决什么,有什么特点

学完了概念,看完了实战,我们来深入 ITCSS 的精髓,Harry Roberts 发明的 ITCSS 不是一个框架,只是组织样式代码的一种方案,既然是方案,那么我么就应该研究下它出现到底是为了解决什么,没错还是 CSS 的老问题,就是 CSS 不支持模块化,全局只有一个作用域,由此导致样式覆盖、混乱。

为了解决,作者发明了 ITCSS,并总结了它三个关键指标来帮你理解。

  1. 通用到显式——explicitness

观察 ITCSS 的分层,我们发现层的权重是层层递进,作用范围却是层层递减,例如,刚开始我们会为浏览器表现一致的样式,采用标签选择器和属性选择器等进行样式重置,落到项目最底层,我们就完全针对当前样式进行修改的。例如先从通用的 h1~6 {},到非常明确的规则 .text-center {}

  1. 低特异性到高特异性——specificity

最低特异性选择器在开始时出现,随着我们的项目进展,特异性稳步增加。我们希望确保尽可能多地避免特异性战争,因此我们尽量避免在低特异性选择器之前编写高特异性选择器。我们总是在同一个方向上添加特殊性,从而避免冲突。

  1. 深远到本地化——reach

项目开始时的选择器会影响很多 HTML 的表现,随着代码的增加,影响范围逐渐缩小。

我们可能首先擦除所有内容的边距和填充,然后我们可能会为每种类型的元素设置样式,然后将范围缩小到应用了特定类的每种类型的元素,依此类推。正是这种逐渐缩小的范围给了我们三角形。

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认