jcLee95 的 博客
邮箱 :291148484@163.com
本文由作者从原 CSDN 上迁移至阿里云
目 录
1. 概述
本文介绍了 原子化 CSS 的相关背景概念、UnoCSS 的特点、用法。通过阅读本文,你可以了解如何使用 这款 CSS 引擎。
2. 原子化 CSS 的概念
2.1 什么是原子化 CSS
所谓 原子化 CSS ,指的是一种用于CSS的架构方式的理念,它倾向于 用途单一的 class,并 以视觉效果进行命名。例如 bootstrap 的颜色系统,为我们提供了直观的颜色名称:
我们可以将这些名称以相似的命名方式构建 css 类:
// Background color .bg-blue-100 { background-color: $blue-100 } .bg-blue-200 { background-color: $blue-200 } .bg-blue-300 { background-color: $blue-300 } .bg-blue-400 { background-color: $blue-400 } .bg-blue-500 { background-color: $blue-500 } .bg-blue-600 { background-color: $blue-600 } .bg-blue-700 { background-color: $blue-700 } .bg-blue-800 { background-color: $blue-800 } .bg-blue-900 { background-color: $blue-900 } // Font color .ft-blue-100 { color: $blue-100 } .ft-blue-200 { color: $blue-200 } .ft-blue-300 { color: $blue-300 } .ft-blue-400 { color: $blue-400 } .ft-blue-500 { color: $blue-500 } .ft-blue-600 { color: $blue-600 } .ft-blue-700 { color: $blue-700 } .ft-blue-800 { color: $blue-800 } .ft-blue-900 { color: $blue-900 } // margin .m-1 { margin: 0.25 rem; } .m-2 { margin: 0.5 rem; } .m-3 { margin: 0.75 rem; } .m-4 { margin: 1 rem; } .m-5 { margin: 1.25 rem; } .m-6 { margin: 1.5 rem; } .m-7 { margin: 1.75 rem; } .m-8 { margin: 2 rem; } .m-9 { margin: 2.25 rem; }
我们可以很直观地使用和调整这些变量值来满足我们实际开发中的需求,同时我们可以通过动控制 DOM 的样式来轻松地对效果进行切换,这在 一些现代前端框架(如vue)中,都可以有很丝滑的体验。
这个例子中的变量为 scss/sass(Sass) 变量,Sass 是目前最强大的前端样式预编译语言,本文在后文中也会有一些涉及它的内容。如果你只会 css,或者还在使用 Less(另一种流行的预编译语言),那么建议你尽早学一下 scss 语法,这十分强大方便,bootstrap、elementPlus 等等多数当前主流框架早以切换到其构建样式系统。
2.2 为什么推荐原子化 CSS
那么为什么要原子化呢。很显然是让代码更 直观可读。另外一方面,从设计师的角度出发,如果我们拿到下面这个语义化的外边距变量名:
.p-1 { margin: 0.25 rem; } .p-2 { margin: 0.5 rem; } /* ... */ .p-9 { margin: 2.25 rem; }
完全就可以对照着呈现效果自己手动更改变量来完成效果切换!
3. 原子化 CSS 的实现实践
3.1原子化初体验
如何才能具备原子化的理念的,实现方法有很多。在一个大项目中为了原子化 CSS,。可以先 提供所有你可能需要用到的 CSS 工具,例如 外边距的大小工具——我们需要约定好一套规范,就像 2.2 小节中的代码那样,使用 p
表示 padding
的简写,使用 数字 1、2、3、… 表示基值的倍数,这里约定基值为 0.25 rem
。
很显然在现实项目中通过手动列举 CSS 类名并逐个描述来完成一套这样的约定是麻烦的,比如在这种情况下为了尽可能简单一点我们会使用 root
为元素中定义一些CSS变量——它们会在不同的原子类中反复用到:
:root { --blue-100: #CEE1FE; --blue-200: #9DC3FC; --blue-300: #69A1F3; --blue-400: #3C89FA; --blue-500: #0D6DFB; --blue-600: ##0A58CA; --blue-700: #084297; --blue-800: #052C65; --blue-900: #031633; --rsize-1: 0.25 rem; --rsize-2: 0.5 rem; --rsize-3: 0.75 rem; --rsize-4: 1 rem; --rsize-5: 1.25 rem; --rsize-6: 1.5 rem; --rsize-7: 1.75 rem; --rsize-8: 2.00 rem; --rsize-9: 2.25 rem; }
然后施展我们的拳脚:
// Background color .bg-blue-100 { background-color: var(--blue-100) } .bg-blue-200 { background-color: var(--blue-200) } // ... .bg-blue-900 { background-color: var(--blue-200) } // Font color .ft-blue-100 { color: var(--blue-100) } .ft-blue-200 { color: var(--blue-200) } // ... .ft-blue-900 { color: var(--blue-900) } // Margin .m-1 { margin: var(--rsize-1) } .m-2 { margin: var(--rsize-1) } // ... .m-9 { margin: var(--rsize-9) }
3.2 使用预编译语言
由于 CSDN 现在仍然不至于预编译语言,相关代码附上高亮截图。
这样是不是依然很麻烦——好在我们可以通过编程来完成。
由于 css 自身并没有这样的能力,以前不得不借助其它语言来生成这样的东西,但如今我们可以使用 如 Sass、Less 这样的预处理器来实现。例如生成 10
p-1
、p-2
、…、p-9
,我们可以使用 @for
指令:
@for $i from 1 through 9 { .m-#{$i} { margin: $i / 4 rem; } }
上面的 @for
指令可以在限制的范围内重复输出格式,其语法格式为:
@for $var from <start> through <end> { // ... style }
或者
@for $var from <start> to <end> { // ... style }
其中:
$var
是迭代变量,可以在块内通过{$var}
的格式来引用;- 当使用
through
时,条件范围包含与
的值,而使用
to
时条件范围只包含的值不包含
的值;
- 和 必须是整数值。
对于颜色值的计算和处理要复杂一些,我们需要用到一些 Sass 内置的一些颜色处理函数,例如 mix
、adjust-hue
、change-color
、scale-color
、desaturate
、transparentize
等等,有兴趣的读者可以看我的另外一篇文章 《sass笔记 - 实战中颜色的玩法总结》。我们可以在 Sass 内置函数的基础上进行二次封装为我们的自定义 Sass 函数,例如:
/** 增加一个颜色的亮度 */ @function tint-color($color, $weight) { @return mix(white, $color, $weight*1%); } /** 降低一个颜色的亮度 */ @function shade-color($color, $weight) { @return mix(black, $color, $weight*1%); } /** 如果权重为正,则阴影,否则着色 */ @function shift-color($color, $weight) { @return if($weight > 0, shade-color($color, $weight*1%), tint-color($color, -$weight*1%)); }
这样我们可以使用一个基础颜色,调用颜色改变函数获得更多不同的颜色应用于更多的CSS类中实现原子化。
例如使用不同的着色百分比给蓝色进行:
$deep-blue: #0000a0; // 一个基础颜色 @for $i from 1 through 100 { .bg-perct-blue-#{$i} { background-color: tint-color($deep-blue, $i); } }
经过编译,会产生以下形式的 CSS 类:
可以看到,仅仅通过少量的代码就生成了一百个 色阶型 的 原子类。
4. UnoCSS - 一款原子化CSS引擎
4.1 UnoCSS 简介与安装
原子化的另外一个决绝方案就是实用一些 JavaScript 模块了,这有时候也是很方便的,比如 Windi CSS 、Tailwind CSS 以及本节我们打算介绍的 UnoCSS。 其中UnoCSS是一款原子化的即时按需 CSS 引擎,其中没有核心实用程序,所有功能都是通过预设提供的。默认情况下 UnoCSS 应用通过预设来实现相关功能。以下是其官方预设:
预设 | 描述 |
@unocss/preset-uno | 默认预设(现在等效于 @unocss/preset-wind )。 |
@unocss/preset-mini | 最小化但必不可少的规则和变体。 |
@unocss/preset-wind | ailwind / Windi CSS CSS紧凑预设。 |
@unocss/preset-attributify | 为其他预设和规则提供归因模式。 |
@unocss/preset-icons | 使用任何图标作为类实用程序。 |
@unocss/preset-web-fonts | 轻松使用网络字体。 |
@unocss/preset-typography | 版式预设。 |
@unocss/preset-tagify | UnoCSS 的标记模式。 |
@unocss/preset-rem-to-px | 将 rem 转换为 px for utils。 |
我们可以通过 npm、yarn、pnpm 等工具(任选一种)安装到你的项目中:
npm i -D unocss # or yarn add -D unocss # or pnpm i unocss -D
4.2 预设(Presets)的使用
对于 vite 项目,可以在你项目 vite.config.ts 配置文件中使用 UnoCSS 的vite插件:
// vite.config.ts import UnoCSS from 'unocss/vite' import { presetAttributify, presetUno } from 'unocss' export default { plugins: [ UnoCSS({ presets: [ presetAttributify({ /* 预设选项 */}), presetUno(), // ...自定义预设 ], }), ], }
其中当指定预设选项时,默认预设将被忽略。因此如果想要禁用默认预设,可以将设置为空的预设数组。
4.3 自定义规则(Rules)
自定义静态规则
你可以通过以下方式自定义一个简单的 UnoCSS 静态规则:
rules: [ ['m-1', { margin: '0.25 rem' }], ['m-2', { margin: '0.5 rem' }], // ... ['m-9', { margin: '2.25 rem' }], ]
每当在用户的代码库中检测到m-1
、m-2
、… 这些名称时,如在
<div class="m-1">My Button</div> <div class="m-2">My Button</div> <!-- ... --> <div class="m-9">My Button</div>
就会生成以下CSS:
.m-1 { margin: 0.25 rem; } .m-2 { margin: 0.5 rem; } // ... .m-9 { margin: 2.25 rem; }
自定义动态规则
更多的情况乱下我们通过正则表达式表示我们的规则会更加实用和方便一些:
rules: [ [/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4} rem` })], ]
这样也避免了枚举,比如我们要用到 .m-100
,显然这样的场景下就需要通过正则表达式定义动态规则的方法来实现了。