CSS设计模式

news/2025/1/10 0:32:48/文章来源:https://www.cnblogs.com/Jannik/p/18663135

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)

<div class="card"><p class="card__element">这是一段文本内容。</p><p class="card__element">这是一段文本内容。</p><p class="card__element card__element--primary">这是一段文本内容。</p>
</div>

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 class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">按钮</button>

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

<button class="btn">按钮</button>

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

const Button = ({ children, color }) => (    <button class=`bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded ${color}`>{children}</button>)

使用如下:

<Button color="pink"> 注册 </Button>

如果样式有修改,我只要插拔 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 CSS,Windi CSS 以及 Tachyons 等。

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

甚至还有一些人根据项目总结出来自己的 ACSS,例如 atom.css、SACSS: 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 的表现,随着代码的增加,影响范围逐渐缩小。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/866854.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【待发】5G新通话的安全卫士——DTLS协议

5G 新通话作为运营商的一种全新通话概念的探索,虽名为通话,实则远不止于此,更是一种实时的沉浸式互动体验。针对 5G 新通话,3GPP 在 R16 阶段完成了 5G 网络 IMS Data Channel 实时交互通道的相关技术标准,并于 2020 年 3 月将其写入并发布了 TS26.114 V16.5.0 版本,实现…

pwn ciscn_2019_n_1 1

可以看到用gets让用户输入v1,还比较了v2的值,但此之前已经设置了v2的值为0.0 法一 可以用传统的方法栈溢出,覆盖返回地址为system的地址法二 v2也存在栈上,也可以通过gets栈溢出修改v2原本的数据 movss xmm0, [rbp+var_4] #将v2的值放到xmm0里面 ucomiss xmm0, cs:dword…

语境学习(in-context-learning)

(高级机器学习的作业,反正写了干脆搬过来)4.1 引言 请考虑这样一句话“该公司预计其营业利润会有所改善。” 可以发现,这句话的情感是积极向上的。我们期待如果把这句话输入给大语言模型,它能够返回“积极(Positive)”这样的词汇。 然而,如果我们直接把这句话输入给大模…

hello-algo

复杂度分析 迭代与递归函数返回前上下文存储在栈帧空间,故递归比迭代耗费更多内存空间 递归调用函数有额外开销,故递归时间效率也更低迭代while循环更灵活,for循环更简洁尾递归和正常递归尾递归会被编译器优化,空间效率相当于迭代!!!原因是尾递归无需保存上下文,正常递…

DataWorks数据分层

在阿里巴巴的数据体系中,我们建议将数据仓库分为三层,自下而上为:数据引入层(ODS,Operation Data Store)、数据公共层(CDM,Common Data Model)和数据应用层(ADS,Application Data Service)。数据仓库的分层和各层级用途如下图所示。数据引入层ODS(Operation Data …

实用且功能丰富的IT工具箱-IT-tools

介绍 IT-Tools是为开发人员度身打造的一套便捷在线工具。 它提供全面功能,使开发者能以更高效方式完成任务。 优秀的用户体验确保用户愉悦使用工具,并获得卓越成果。 经由IT-Tools,开发人员能轻松应对各类技术挑战,享受工作中的便利与灵活。 官网正式稳定版在线版正式稳定版…

《CPython Internals》阅读笔记:p61-p75

《CPython Internals》学习第 4 天,p61-p75 总结,总计 15 页。 一、技术总结 1.编译器类型 (1)self-hosted compiler Self-hosted compilers are compilers written in the language they compile, such as the Go compiler. This is done by a process known as bootstrap…

ETHERCAT转CCLINK网关对接ethercat通讯协议的高效解析指南

在某汽车零部件制造工厂的自动化生产线升级项目中,部分关键设备采用了支持 ETHERCAT 总线的 PLC 进行控制,而工厂原有的一些设备则遵循 CCLINK 协议标准。由于这两种协议之间无法直接通信,导致生产线的数据交互受阻,难以实现整体的协同运作与高效管理,迫切需要一种可靠的解…

妙用编辑器:列编辑在编写Markdown表格时的使用技巧

1 妙用编辑器:列编辑在编写Markdown表格时的使用技巧经常写Markdown笔记的朋友应该清楚,Markdown的表格比较麻烦,定义表格每列时需要使用|线进行绘制表格边界。比如有下面一段文字名称, 大小, 类型, 修改, 属性 …

Python用K-Means均值聚类、LRFMC模型对航空公司客户数据价值可视化分析指标应用

全文链接:https://tecdat.cn/?p=38708 原文出处:拓端数据部落公众号 分析师:Yuling Fang 信息时代的来临使得企业营销焦点从产品中心转向客户中心,客户关系管理成为企业的核心问题。客户关系管理的关键是客户分群,通过客户分群,区分无价值客户和高价值客户,同时更好的了…

【专题】2024年直播、短视频:抖音、小红书、快手行业报告汇总PDF合集分享(附原数据表)

原文链接: https://tecdat.cn/?p=38697 在当今数字化飞速发展的时代,直播、短视频行业已然成为了大众生活与商业运作中不容忽视的重要力量,正不断重塑着信息传播与消费的格局。 2024 年,这一领域更是呈现出多元且复杂的发展态势。从内容创作者生态来看,抖音、小红书、快手…

卫龙 IPO 多维度分析及运营创新解析报告-CSDN博客

全文链接: https://tecdat.cn/?p=38686 分析师:Dichuan Zheng 一、报告概述 本报告旨在对卫龙的 IPO 相关情况展开全面分析,涵盖外部环境、波特五力、内部状况、商业模式以及价值链等多方面内容,通过梳理卫龙的发展历程、关键要素等,为了解其上市背景及发展潜力提供参考依…