本人在生产项目中使用 UnoCSS 已经快两年了。前段时间在公司无脑整理了培训文档和我常用的一些小技巧,现在将排除项目内部代码之外的内容分享出来。
一、安装
在 Vue3 + Vite 项目中安装
安装 UnoCSS。
pnpm add -D unocss
在 Vite 中注册插件。
// vite.config.ts
import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
UnoCSS(),
],
})
创建 uno.config.ts
文件,当然你也可以直接在 vite.config.ts
中进行简单配置。
// uno.config.ts
import { defineConfig } from 'unocss'
export default defineConfig({
// ...UnoCSS options
}
在 mian.ts
中导入。
// main.ts
import 'virtual:uno.css'
在 Nuxt 3 中安装
安装 UnoCSS 。
pnpm add -D @unocss/nuxt
在 Nuxt 中注册模块。
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@unocss/nuxt',
],
})
创建 uno.config.ts
文件,当然你也可以直接在 nuxt.config.ts
中进行简单配置。
// uno.config.ts
import { defineConfig } from 'unocss'
export default defineConfig({
// ...UnoCSS options
})
此外,除了 Vue 和 Nuxt,UnoCSS 还支持 React、Next、Remix、Astro、Svelte、Webpack、PostCSS Plugin、uni-app 等。
二、UnoCSS 基础用法
交互式文档
交互式文档实际演示如下内容:
- flex
- width
- colors
- mdn:
- padding & margin
基础语法
- 文字
<div class="text-4xl font-600 font-italic underline lh-tight">
文字
</div>
- 边框
<div class="border-2 rd-2xl border-dashed inline-block lh-10 text-4xl lh-20">
文字
</div>
- 边距
<div class="p-x-4 py-8 mb-2 mt-3 inline-block border-2">
边距
</div>
- 宽高
<div class="w-40 h-30 border-2 py-2">
<div class="h-full w-screen border-dashed border-1">宽高</div>
</div>
- 颜色
<div class="w-40 h-30 bg-stone p-2">
<div class="bg-pink op-30 mb-2">背景</div>
<div class="bg-blue color-green p-2">颜色</div>
</div>
- flex布局
<div class="w-xs">
<h1 class="mb-2">Flex 布局</h1>
<div class="flex items-center justify-between border-1 mb-1 px-1">
<div>flex-1</div>
<div>flex-2</div>
<div>flex-3</div>
</div>
<div class="flex items-center justify-end gap-3 border-1 mb-1 px-1">
<div>flex-1</div>
<div>flex-2</div>
<div>flex-3</div>
</div>
<div class="flex flex-col gap-1 border-1 px-1">
<div>flex-1</div>
<div>flex-2</div>
</div>
</div>
- 定位
<div class="w-xs border-1 p-2 relative">
父元素
<div class="absolute top-2 right-10 zindex-100">
子元素
</div>
</div>
- 动画
<div class="border-1 relative w-40 hover:transform-rotate-50 transition-all">
<div class="transform-rotate-10 translate-x-10 cursor-pointer">
动画
</div>
</div>
- important
<div class="w-xs border-1 p-2 text-4xl">
父元素
<div class="!text-2xl">
子元素
</div>
</div>
IDE 插件提示
三、Iconify SVG
官方文档:iconify.design/
官方图标库:icon-sets.iconify.design/
Icones 图标库:icones.js.org/
安装
pnpm add -D @unocss/preset-icons @iconify-json/[the-collection-you-want]
我个人常用的是:@iconify-json/carbon 和 @iconify-json/remix。
如果你想开发模式下下载全部图标(它是按需编译的,不用担心编译后的体积):
pnpm add -D @iconify/json # 该全量包约为 130MB
在 uno.config.ts
中配置 presetIcons 插件。
presetIcons({
extraProperties: {
'prefix': 'i-',
'display': 'inline-block',
'vertical-align': 'middle',
// ...
},
})
UnoCSS 使用 SVG 图标
- 基础用法
通过 class 使用 SVG 图标。
<div class="p-4">
<div class="i-carbon-3d-curve-auto-colon " />
</div>
- 图标大小
<div class="p-4 flex items-center">
<div class="i-ri-bluesky-line text-3xl" />
</div>
- 颜色
<div class="p-4 flex items-center">
<div class="i-ri-bluesky-line text-3xl color-blue" />
</div>
- 切换效果
<div class="text-3xl i-twemoji-grinning-face-with-smiling-eyes hover:i-twemoji-face-with-tears-of-joy" />
本地SVG压缩
如果需要进一步压缩本地 SVG 文件的体积,你可以安装 svgo 插件进行压缩。
pnpm add -g svgo
通过命令:svgo -f path -o path
即可进行压缩处理。
更多压缩语法与配置文件请参考:github.com/svg/svgo/
四、UnoCSS Preset
Icons preset
你可以通过这个插件来使用 SVG 图标,前面在 ## Iconify SVG 章节已经介绍过了。
// uno.config.ts
import { defineConfig, presetIcons } from 'unocss'
export default defineConfig({
presets: [
presetIcons({ /* options */ }),
// ...other presets
],
})
下面是一些常用的配置项,更多内容需要参考官方文档。
- 通过
scale
配置可以设置默认的缩放大小。 - 通过
prefix
可以设置 class 前缀。 - 通过
extraProperties
可以设置默认的 CSS 样式。
这是我的常用配置:
presetIcons({
scale: 1.2,
prefix: 'i-',
extraProperties: {
display: 'inline-block',
},
})
此外,该插件支持配置 CDN 加载、本地加载、按需加载和自定义 SVG 图标 class,具体参考官方文档:unocss.dev/presets/ico…。
Attributify preset
该插件提供 html 标签的attribute 写法支持。
// uno.config.ts
import { defineConfig, presetAttributify } from 'unocss'
export default defineConfig({
presets: [
presetAttributify({ /* preset options */ }),
// ...
],
})
配置后无需通过声明 class=""
也可书写样式,并且支持组合写法。
<button
w-50
bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"
text="sm white"
font="mono light"
p="y-2 x-4 l-2 r-2 b-2 t-2"
border="2 rounded blue-200"
>
我不需要写 class
</button>
这样的写法在常规的 html 标签上没有问题,如果是针对自定义的组件,如果组件内部封装的属性与样式冲突,则可以通过 un-
的前缀避免这个问题。
<MyText text="red">与组件的 text 属性冲突</MyText>
<MyText un-text="red">使用前缀设置颜色,不会冲突</MyText>
更多配置项和 TS 类型支持,请参考官方文档:unocss.dev/presets/att…。
Web Fonts preset
UnoCSS 使用字体插件。
// uno.config.ts
import { defineConfig, presetWebFonts } from 'unocss'
export default defineConfig({
presets: [
presetWebFonts({ /* options */ }),
],
})
该插件可以使用默认提供的字体,如 google``bunny``fontshare
,如果配置为 none
则使用系统默认字体。
下面是我的常用字体配置:
presetWebFonts({
fonts: {
sans: 'Inter:400,600,800',
mono: 'DM Mono:400,600',
},
})
上面配置字体的写法为:font-sans
针对网络不好的环境或者需要自定义字体包的使用场景,插件支持通过 customFetch
手动配置:
// uno.config.ts
import { defineConfig } from 'unocss'
import presetWebFonts from '@unocss/preset-web-fonts'
import presetUno from '@unocss/preset-uno'
import axios from 'axios'
import ProxyAgent from 'proxy-agent'
export default defineConfig({
presets: [
presetUno(),
presetWebFonts({
// use axios with an https proxy
customFetch: (url: string) => axios.get(url, { httpsAgent: new ProxyAgent('https://localhost:7890') }).then(it => it.data),
}),
],
})
Rem to px preset
UnoCSS 所有的样式均为 rem
单位(value: 16px),如果不需要 rem
单位,可以通过该插件转成 px
。
// uno.config.ts
import { defineConfig, presetRemToPx } from 'unocss'
export default defineConfig({
presets: [
presetRemToPx(),
// ...other presets
],
})
五、UnoCSS Transformer
Variant group transformer
该插件提供包裹多个 class 。
// uno.config.ts
import { defineConfig, transformerVariantGroup } from 'unocss'
export default defineConfig({
// ...
transformers: [
transformerVariantGroup(),
],
})
<div class="hover:(bg-gray-400 font-medium) font-(light mono)"/>
上面的代码等同于:
<div class="hover:bg-gray-400 hover:font-medium font-light font-mono"/>
Directives transformer
该插件提供在 css 里使用原子化 class。
// uno.config.ts
import { defineConfig, transformerDirectives } from 'unocss'
export default defineConfig({
// ...
transformers: [
transformerDirectives(),
],
})
- 使用
@apply
或者--at-apply
进行使用:
如果不想用默认的 --at-apply ,可以通过配置参数修改。
.custom-div {
@apply text-center my-0 font-medium;
}
/* --at-apply 兼容性更好 */
.custom-div {
--at-apply: text-center my-0 font-medium;
}
- 使用
@screen
来开发响应式:
.grid {
--uno: grid grid-cols-2;
}
/* @screen xs 会转成 --> @media (min-width: 320px) */
@screen xs {
}
@screen sm {
}
/* 也可以使用 lt 设置 max-width */
@screen lt-xs{
}
/* 也可以使用 at 设置 and */
@screen at-xs{
}
- 如果你需要使用主题,可以使用
theme()
css 函数:
.btn-blue {
background-color: theme('colors.blue.500');
}
Attributify JSX transformer
插件支持在 JSX 合 TSX 中以属性写法写样式。
// uno.config.ts
import { defineConfig, presetAttributify, transformerAttributifyJsx } from 'unocss'
export default defineConfig({
// ...
presets: [
// ...
presetAttributify(),
],
transformers: [
transformerAttributifyJsx(), // <--
],
})
使用举例:
export function Component() {
return (
<div text-red text-center text-5xl animate-bounce>
unocss
</div>
)
}
Compile class transformer
插件支持将多个 class 编译成一个。
// uno.config.ts
import { defineConfig, transformerCompileClass } from 'unocss'
export default defineConfig({
// ...
transformers: [
transformerCompileClass(),
],
})
使用举例:
<div class=":uno: text-center sm:text-left">
<div class=":uno: text-sm font-bold hover:text-red"/>
</div>
编译结果:
<div class="uno-qlmcrp">
<div class="uno-0qw2gr"/>
</div>
.uno-qlmcrp {
text-align: center;
}
.uno-0qw2gr {
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 700;
}
.uno-0qw2gr:hover {
--un-text-opacity: 1;
color: rgb(248 113 113 / var(--un-text-opacity));
}
@media (min-width: 640px) {
.uno-qlmcrp {
text-align: left;
}
}
六、UnoCSS 常用使用技巧
shortcuts 组合 class
通过 shortcuts 将多个 class 组合成一个。该配置通常用于全局样式、主题、背景等。
export default defineConfig({
shortcuts: [
{
'bg-main': 'bg-hex-eef5fc dark:bg-hex-0d1117',
'text-main': 'text-hex-555555 dark:text-hex-bbbbbb',
'text-link': 'text-dark dark:text-white ',
'border-main': 'border-truegray-300 dark:border-truegray-600',
},
{
'text-title': 'text-link text-4xl font-800',
'nav-link': 'text-link opacity-70 hover:opacity-100 transition-opacity duration-200 cursor-pointer',
'prose-link': 'text-link text-nowrap cursor-pointer border-b-1 !border-opacity-30 hover:!border-opacity-100 border-neutral-500 hover:border-truegray-600 dark:border-neutral-500 hover:dark:border-truegray-400 transition-border-color duration-200 decoration-none',
'container-link': 'p-2 opacity-60 hover:opacity-100 cursor-pointer hover:bg-truegray-500 !bg-opacity-10 transition-colors transition-opacity duration-200',
},
{
'hr-line': 'w-14 mx-auto my-8 border-solid border-1px !border-truegray-200 !dark:border-truegray-800',
},
]
})
这是一个 Astro 项目中的一段示例代码
<html lang="en">
<head>
<BaseHead {...head} />
<ViewTransitions />
</head>
<body class="bg-main text-main min-h-screen font-sans w-full bg-dot">
<Header client:load />
<main
class="grow max-w-3xl mx-auto sm:pt-36 pt-26 pb-16 px-6 relative"
transition:animate={fade({ duration: '0.4s' })}
>
<slot />
<ScrollToTop client:load />
<Footer />
</main>
</body>
响应式样式
通过 sm:xxx
等写法即可快速实现响应式样式。
如下面一段代码,在宽度大于 640px 时会隐藏菜单图标。
<div class="flex items-center h-full">
<a href="/" mr-6 aria-label="Header Logo Image">
<img width="32" height="32" :src="siteConfig.header.logo.src" :alt="siteConfig.header.logo.alt">
</a>
<nav class="sm:flex hidden flex-wrap gap-x-6 position-initial flex-row">
<a
v-for="link in navLinks" :key="link.text" :aria-label="`${link.text}`" :target="getLinkTarget(link.href)"
nav-link :href="link.href"
>
{{ link.text }}
</a>
</nav>
<div sm:hidden h-full flex items-center @click="toggleNavDrawer()">
<menu i-ri-menu-2-fill />
</div>
</div>
其他媒体查询breakpoints前缀和对应的宽度如下:
- sm, 640px
- lg, 1024px
- xl, 1280px
safelist与图标动态加载
在菜单或者动态配置的图标,以及动态 class 场景下,需要预加载图标才能正确显示。
可以通过如下方式实现:
- 使用 safelist;
import { defineConfig } from 'unocss'
export default defineConfig({
safelist: [
'i-ri-file-list-2-line',
'i-carbon-campsite',
],
})
- 列出所有组合的对象,然后动态引用;
const classes = {
icon1: 'i-ri-file-list-2-line',
icon2: 'i-carbon-campsite'
}
<div :class="classes.icon2" />
- 通过配置文件
该方式,可以将所有的动态 class 放到单独的文件中,使用 // @unocss-include
进行编译。
也可以配置 filesystem 指定文件。
// uno.config.ts
export default defineConfig({
content: {
filesystem: [
'src/**/*.css',
],
},
})
自定义 class 规则
通过配置 shortcuts 或者 rules 即可自定义规则。
- 通过 rules 即可覆盖默认的规则。
rules: [
// 覆盖默认的规则
['font-bold', { 'font-weight': 700 }],
// 正则生成规则
[/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
]
也支持选择器、特殊符号等生成,更多写法参考文档:unocss.dev/config/rule…
- 通过 shortcuts 可以将多个 class 组合为单个 class。
shortcuts: {
// 组合多条 class
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
// 直接使用已经组合好的 class
'btn-green': 'btn text-white bg-green-500 hover:bg-green-700',
// 单个 class 声明别名
'red': 'text-red-100',
// 根据正则动态生成 class
[/^btn-(.*)$/, ([, c]) => `bg-${c}-400 text-${c}-100 py-2 px-4 rounded-lg`],
}
自定义主题及覆盖
通过配置 theme 可设置主题系统,默认提供 tailwind css 或者 windi css 的主题。
theme: {
// ...
bg
colors: {
'veryCool': '#0000ff', // class="text-very-cool"
'brand': {
'primary': 'hsl(var(--hue, 217) 78% 51%)', //class="bg-brand-primary"
},
},
}
使用时:
<div class="bg-brand-primary">
<a class="color-brand-primary">链接</a>
</div>
theme 配置支持覆盖媒体查询断点,如把 sm 修改为 320px。
theme: {
// ...
breakpoints: {
sm: '320px',
md: '640px',
},
}
class 自定义颜色值
如果 unocss 预设的颜色不能满足需求,可以通过如下方式自定义颜色值。
- 使用 class 直接声明颜色值,
class="bg-#000 bg-hex-fff"
; - 使用 attribute 写法直接声明颜色值,
bg="#000"
;
基于vueuse的黑暗模式
<i i="carbon-sun dark:carbon-moon" @click="toggleDark()" />
常用 class 简写和写法
- flex 简写,
<div flex="~ items-center gap-2" />
; - margin 和 padding 简写,如:
<div m-1 ml-1 mx-1 m-x-1 mt-1 mt-1.5px m="1 0" />
; - 宽高度简写,
<div h-1 h-auto h-full h-screen min-h-1 min-h-2vw max-h-50px />
; - 负数,
<div h--1 h--10px m--1 />
; - 圆角,
<div rounded rd-1 rd-full rd="1 0" />
; - !important,
<div !flex />
; - 鼠标样式,
<div cursor-pointer />
; - 禁用,
<div disabled:cursor-default />
;