深度了解后的UnoCSS
之前介绍过Tailwind CSS和UnoCSS,可以看这篇文章TailwindCSS vs UnoCSS:两大原子化CSS框架深度对比与最佳使用场景。
最近我在项目中集成了UnoCSS,使用了一段时间,发现了它的优势与缺点,这篇文章就来细说一下我使用UnoCSS的感受。
1. 集成
因为Tailwind CSS 3出现了一个十分重要的新特性,那就是可以使用自定义类名,比如:px-[10px]
这种写法,而在Tailwind 2中,这是不被支持的。
所以我最常用使用的是Tailwind CSS 3,但是Tailwind 3的集成有一个前置条件,那就是需要使用PostCSS 8,而在Vue-cli 4中,它默认集成的是PostCSS 7,而且还无法被替换,如果你想要使用PostCSS 8,那么将Vue-cli升级到5。
非常不巧的是,我们现在公司使用的项目年代已经非常久了,都是使用的Vue 2,并且已经迭代了好几年,而我主要负责的项目是小程序端,小程序使用Uniapp Vue 2的版本,Uniapp甚至在Vue-cli上面又再次封装了一层,就导致更难以使用到PostCSS 8。
经过我的研究后,我发现UnoCSS不需要PostCSS的支撑,也能集成到Vue 2的项目中。
而在Vue-cli 4中,我经过了很久的研究,发现需要使用0.48.9
这个版本,因为从0.49.0
开始,UnoCSS就只支持ESM的方式引入,可以参考官方文档@unocss/webpack。
如果使用0.49.0
以及后面的版本,需要通过下面的方式引入:
// vue.config.js
const process = require('node:process')
module.exports = function () {
return import('@unocss/webpack').then(({ default: UnoCSS }) => ({
configureWebpack: {
devtool: 'inline-source-map',
plugins: [
UnoCSS()
],
optimization: {
realContentHash: true
}
},
chainWebpack(config) {
config.module.rule('vue').uses.delete('cache-loader')
config.module.rule('tsx').uses.delete('cache-loader')
config.merge({
cache: false
})
},
css: {
extract: process.env.NODE_ENV === 'development'
? {
filename: 'css/[name].css',
chunkFilename: 'css/[name].css'
}
: true
}
}))
}
但我研究后发现,这种引入方式会报错,可能是因为UnoCSS内部的依赖问题,也可能是webpack的版本问题,总之就是无法正常使用。
所以最后我选择了0.48.9
这个版本,然后使用UnoCSS的默认配置,通过vue.config.js
引入。
npm install -D @unocss/[email protected] [email protected]
// vue.config.js
const process = require('node:process')
const UnoCSS = require('@unocss/webpack').default
module.exports = {
configureWebpack: {
devtool: 'inline-source-map',
plugins: [
UnoCSS()
],
optimization: {
realContentHash: true
}
},
chainWebpack(config) {
config.module.rule('vue').uses.delete('cache-loader')
config.module.rule('tsx').uses.delete('cache-loader')
config.merge({
cache: false
})
},
css: {
extract: process.env.NODE_ENV === 'development'
? {
filename: 'css/[name].css',
chunkFilename: 'css/[name].css'
}
: true
},
}
这种方式则可以正常使用,至于unocss.config.js
文件,直接写入下面的代码:
// uno.config.js
const { defineConfig, presetUno, presetAttributify } = require('unocss')
module.exports = defineConfig({
presets: [
presetUno(),
presetAttributify()
]
})
但需要注意的是,UnoCSS需要使用Node 18以上的版本,我尝试过这样引入后,项目的启动会非常快,但是项目启动后,UnoCSS不会被编译,需要修改一下文件,然后保存一下,UnoCSS才会被编译。
1.1 小程序
因为微信小程序是无法使用px-[10px]
这种类的,所以需要靠第三方库来解决。
我们的小程序是用的Uniapp 2,Uniapp 2的Vue 2版本是用的Vue-cli 4,参考这个unocss-webpack-uniapp2,那么需要安装以下的依赖:
npm install -D unocss unocss-webpack-uniapp2 unocss-preset-weapp
然后按照它的文档上面,就可以很容易集成到项目中。
2. 深度使用
由于我之前自定义了很多Tailwind CSS的规则,所以如果要迁移到UnoCSS,需要重新自定义很多规则。
然后我就研究了一下UnoCSS的presets、rules、transformers。
2.1 presets
presets是UnoCSS的预设,它可以帮助我们快速生成很多规则,比如要兼容Tailwind的写法,就可以使用@unocss/preset-wind
这个库。
UnoCSS目前支持多种预设,包括:
- presetUno: 默认预设,结合了多个框架的常见功能
- presetWind: 兼容Tailwind CSS的语法
- presetAttributify: 支持属性化模式,如
<div bg="blue-400" text="sm white">
- presetIcons: 支持使用纯CSS图标
- presetTypography: 提供排版样式
- presetWebFonts: 方便使用网络字体
2.2 rules
rules是UnoCSS生成CSS的规则,可以让你将任意的类名写法,生成你想要的规则,比如:
rules: [
['px-1', { 'padding-left': '1px', 'padding-right': '1px' }]
]
这个代码对应的CSS就是:
.px-1 {
padding-left: 1px;
padding-right: 1px;
}
最重要的是它可以动态生成规则,比如:
rules: [
[/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
[/^p-(\d+)$/, match => ({ padding: `${match[1] / 4}rem` })],
]
这个代码对应的CSS就是:
.m-1 {
margin: 0.25rem;
}
.p-1 {
padding: 0.25rem;
}
并且它可以匹配到m-
、p-
所有写法。
2.3 transformers
transformers是UnoCSS的转换器,它可以将类名转换成为其它的类名,比如小程序这种不支持px-[10px]
,使用transformers就可以转换成px-10px
或者px-10
这种写法。
UnoCSS提供了以下转换器:
- transformerVariantGroup: 支持组合多个变体,如
hover:(bg-gray-400 font-medium)
- transformerDirectives: 支持在CSS中使用
@apply
等指令 - transformerAttributifyJSX: 针对JSX属性化模式的优化
- transformerCompileClass: 可以编译类名为其他格式
格局再打开一点,它甚至可以将px-[10px]
这种写法,转换为px-[20rpx]
这种写法,然后由UnoCSS生成对应的CSS。
至于其它的配置,可以看一下unocss.dev/config/。
3. 优点与缺点
说完了如何集成,那么我就来说一下相关的优点与缺点,当然这是对比Tailwind CSS来说的。
3.1 优点
- 更灵活的配置体系 - 比Tailwind更丰富的配置,你可以实现各种类与类的转化。
- 更好的兼容性 - 可以兼容Tailwind的写法,而Tailwind无法兼容UnoCSS的写法。
- 更简单的集成 - 不依赖PostCSS就可以集成,所以如果是Vue 2的老项目,可以无压力集成。
- 卓越的性能 - 性能极佳,根据基准测试,UnoCSS比Tailwind快约200倍,资源消耗更少。
- 原生图标支持 - 对纯CSS图标的支持,让你可以使用任何来自Iconify的图标作为单个类。
- 强大的扩展性 - 可以轻松创建自己的规则和预设,定制性更强。
- 变体组功能 - 提供了变体组功能,可以让多个状态变体更加整洁,如
hover:(bg-blue-500 text-white)
。
3.2 缺点
- 写法过于自由 - 写法太过于自由,如果是多人开发,会让项目中的类名变得非常繁杂,比如
px-10px
和px-[10px]
都是可行的。而Tailwind CSS的写法是固定的,比如只有px-[10px]
。 - 稳定性问题 - 不如Tailwind稳定,我个人在使用过程中,无论是集成上,还是使用上,都遇到了不少问题,而Tailwind CSS一旦集成成功,很少遇到其它问题。
- 文档体验 - 虽然文档全面但有时不够直观,新手上手可能需要更多时间,而Tailwind CSS的文档结构清晰、示例丰富。
- 生成静态CSS文件限制 - 不能直接根据项目代码生成独立的CSS文件,从而不破坏项目结构。这在某些特定场景下可能是个限制。
Tailwind是可以直接根据项目代码,生成CSS文件,我之前一直是以这种方法,将Tailwind应用到项目中。
因为Tailwind提供了一个CLI工具,只需要使用:
npx tailwindcss -i ./src/assets/css/tailwind.css -o ./src/assets/css/tailwind.output.css --watch
然后就可以在项目中使用Tailwind CSS的写法,然后Tailwind CSS会根据项目代码,生成CSS文件,然后我们只需要在项目中引入这个CSS文件即可。
但这么使用有几个缺点:
- Tailwind CSS有一部分特性无法使用,比如
@apply
- Tailwind CSS CLI在处理大型项目时会占用大量内存,有时会因为内存不足而崩溃
- 在Uniapp项目中,每次保存代码都会触发两次编译(一次是Uniapp的编译,一次是Tailwind的编译),导致开发效率降低
而UnoCSS的优势之一就是其高效的按需编译机制,几乎不会有内存问题,编译速度也快得多。根据官方基准测试,UnoCSS的性能可以比Tailwind JIT快200倍,这在大型项目中尤为明显。
4. 总结
UnoCSS的优点是比Tailwind更丰富的配置,可以兼容Tailwind的写法,但是Tailwind无法兼容UnoCSS的写法。性能方面,UnoCSS远超Tailwind,占用更少的系统资源,编译速度更快。此外,UnoCSS提供了许多创新功能,如纯CSS图标、变体组、属性化模式等,这些都是Tailwind所不具备的。
UnoCSS的缺点是写法太过于自由,如果是多人开发,会让项目中的类名变得非常繁杂。另外,对于新手来说,UnoCSS的灵活性可能反而会增加学习成本,而Tailwind更加结构化的方法可能更容易掌握。
我个人建议:
- 如果项目是全新的,且团队熟悉Tailwind:优先考虑使用Tailwind CSS,因为它的写法固定,使用更加稳定,可以让项目风格更加统一。
- 如果是Vue 2的老项目或需要高性能:考虑使用UnoCSS,特别是如果你的项目规模较大或有性能问题,UnoCSS的高效性能可能会带来显著改善。
- 如果不想破坏现有架构:使用Tailwind CSS的生成CSS文件的方式是一个完全没有风险的方案,相当于给项目中引入了一个CSS文件。不过要注意内存占用和双重编译可能带来的开发体验问题。
随着UnoCSS的不断发展和改进,它已经成为了原子化CSS领域的一个强有力的竞争者。它不仅在性能上有明显优势,还提供了许多创新功能。但根据项目需求和团队情况,选择最适合的工具仍然是最重要的。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!