公司内部 UnoCSS 培训文档,含日常使用小技巧,赶紧收藏起来!

4,229 阅读7分钟

本人在生产项目中使用 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 />