前置知识
什么是原子化 CSS
原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class,并且会以视觉效果进行命名。
为什么使用 原子化 CSS
传统方案
制作原子化 CSS 的传统方案其实就是提供所有你可能需要用到的 CSS 工具。例如,你可能会用预处理器(这里选用的是 SCSS)生成如下代码:
// style.scss@for $i from 1 through 10 {.m-#{$i} {margin: $i / 4 rem;}
}
编译结果为:
.m-1 { margin: 0.25 rem; }
.m-2 { margin: 0.5 rem; }
/* ... */
.m-10 { margin: 2.5 rem; }
现在你可以直接使用 class="m-1"
来设置边距。但正如你所见,用这种方法的情况下,你不能使用除了 1 到 10 之外的边距,而且,即使你只使用了其中一条 CSS 规则,但还是要为其余几条规则的文件体积买单。如果之后你还想支持不同的 margin 方向,使用比如 mt
代表 margin-top
,mb
代表 margin-bottom
等,加上这 4 个方向以后,你的 CSS 大小会变成原来的 5 倍。如果再有使用到像 :hover
和 :focus
这样的伪类时,体积还会得更变大。以此类推,每多加一个工具类,往往意味着你 CSS 文件的大小也会随之增加。这也就是为什么传统的 Tailwind 生成的 CSS 文件会有数 MB 的大小。
为了解决这个问题,Tailwind 通过使用 PurgeCSS 来扫描你的打包产物并删除你不需要的规则。这得以使其在生产环境中 CSS 文件缩减为几 KB。然而,请注意,这个清除操作仅在生成构建下有效,而开发环境下仍要使用包含了所有规则巨大的 CSS 文件。这在 Webpack 中表现可能并不明显(项目过大也会有着巨大影响),但在 Vite 中却有着巨大的影响,毕竟其他内容的加载都非常迅捷。
Tailwind对比unocss
例如,我们知道 Tailwind 中的 border-2
标识边框宽度为 2px
,4
表示 4px
,6
表示 6px
,8
表示 8px
,但当你使用 border-10
却不起作用(你甚至需要一些时间来发现这件事!)。你可能会说这是故意而为之,以使得设计系统具有一致性。不如这样,我们来做个小测验,如果想要让 border-10
正常工作,应该如何做?
在你的全局样式中的某个位置添加这样一个工具类?
.border-10 {border-width: 10px;
}
快速且直观,最重要的是,它的确解决了你的需求。但是,如果什么都需要我自己手动添加,那我们为什么还需要使用 Tailwind ?
可参考文章
重新构想原子化 CSS
UnoCSS官方中文文档 指南
自 2023 年 3 月起不再积极维护windicss官方文档 Getting Started | Windi CSS
使用unocss
在vscode编辑器中安装unocss插件 能友好的提示
npm i -D unocss
vite.config.ts
import unocss from 'unocss/vite'plugins: [vue(), vueJsx(),unocss({rules:[
//配置自定义规则 ['U-flex', { display: "flex" }]]})],
main.ts 引入
import 'uno.css'
1 配置自定义规则
rules: [['flex', { display: "flex" }]
]
<template><divclass="u-flex">什么是原子化CSS</div>
</template><script setup lang="ts">
import { ref, reactive } from "vue";
</script><style lang="less" scoped></style>
效果图:
2 配置动态css(使用正则表达式)
m-参数 例如 m-10 就是 margin:10px
rules: [[/^m-(\d+)$/, ([, d]) => ({ margin: `${Number(d) * 10}px` })],['flex', { display: "flex" }]
]
3 .shortcuts 可以自定义组合样式
plugins: [vue(), vueJsx(), unocss({rules: [['pink', { color: 'pink' }]],shortcuts: {btn: "pink flex"}})],
4 unocss 预设
presets:[presetIcons(),presetAttributify(),presetUno()]
4.1.presetIcons Icon图标预设
图标集合安装
npm i -D @iconify-json/ic
首先我们去icones官网(方便浏览和使用iconify)浏览我们需要的icon,比如这里我用到了Google Material Icons图标集里面的baseline-add-circle图标
比如你想使用Element Plus的图标库 直接查询后能看到网址https://icones.js.org/collection/ep
能看到是/ep结尾的 下载命令就是
npm i -D @iconify-json/ep
不加/ep就是下载所有的图标库体积会特别大
4.2.presetAttributify 属性化模式支持
属性语义化 无须class
vite.config.ts
import { defineConfig, presetAttributify, presetUno } from 'unocss'export default defineConfig({presets: [presetAttributify({ /* preset 选项 */}),presetUno(),// ...自定义 presets],
rules:[]
})
<div font="black">btn</div><buttonclass="bg-blue-400 hover:bg-blue-500 text-sm text-white font-mono font-light py-2 px-4 rounded border-2 border-blue-200 dark:bg-blue-500 dark:hover:bg-blue-600">未使用属性化模式支持 css Button</button><buttonbg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"text="sm white"font="mono light"p="y-2 x-4"border="2 rounded blue-200">使用属性化模式支持Button</button><div w20 h20 bg-blue-500>使用属性化模式支持Button 省略class后无类名提示。。。</div>
4.3.presetUno 工具类预设
tips:默认的预设是基于Windi CSS的注意margin 和border的单位是px,其他样式是rem
默认的 @unocss/preset-uno 预设是一系列流行的原子化框架的 通用超集,包括 Tailwind CSS、Windi CSS、Bootstrap、Tachyons 等。
例如,ml-3
(Tailwind CSS)、ms-2
(Bootstrap)、ma4
(Tachyons)和 mt-10px
(Windi CSS)都是有效的。
.ma4 { margin: 1rem; }
.ml-3 { margin-left: 0.75rem; }
.ms-2 { margin-inline-start: 0.5rem; }
.mt-10px { margin-top: 10px; }
4.4 Rem to px 预设
将所有工具类中的 rem 转换为 px。
pnpm add -D @unocss/preset-rem-to-px
// uno.config.ts
import { defineConfig } from 'unocss'
import presetRemToPx from '@unocss/preset-rem-to-px'export default defineConfig({presets: [presetRemToPx(),// ...other presets],
})