前言

原子化CSS(Atomic CSS)是近年来提出的一种架构方法,与之有区别的是咱们比较常用的组件化书写方法。今天介绍的是AntFu的开源新作原子化CSS引擎—UnoCSS。

AntFu 在开发Vitesse是运用 Tailwind CSS 作为 Vitesse 的默许 UI 结构。但由于 Tailwind 生成了数 MB 的 CSS,使得加载与更新 CSS 成为了整个 Vite 应用的性能瓶颈。后来作者发现了Windi CSS,比较于 Tailwind CSS 具有按需加载,零依赖等特性。

由于作者是vite团队成员,所以该文事例所用的构建东西也将选用vite

事例技术桟:Pnpm+Vite+Vue3

什么是原子化

John Polacek 在 文章 Let’s Define Exactly What Atomic CSS is 中有一个界说:

Atomic CSS is the approach to CSS architecture that favors small, single-purpose classes with names based on visual function

译文:

原子化 CSS 是一种 CSS 的架构方法,它倾向于细巧且用途单一的 class,并且会以视觉效果进行命名。

单纯的界说并不够直观,你能够理解为下面的CSS书写方法便是原子化CSS,细心发现它的类名和款式值是有着强关联的。

这是一个简单的比如

<div  class="m-0 text-red" />
.m-0 {
  margin: 0;
}
.text-red {
  color: red;
}
/* ... */

原子化vs组件化

原子化

  1. 减少了CSS体积,提高了CSS复用

  2. 减少起名的复杂度

  3. 增加了回忆本钱 将CSS拆分为原子之后,你势必要记住一些class才干书写,哪怕tailwindCSS供给了完善的东西链,你写background,也要记住最初是bg

  4. 或许会造成class名过长的问题

组件化

  1. CSS体积增加

  2. 起名难

综上,原子化和组件化相结合似乎是更好的方向。

常见原子化CSS结构

在正式介绍UnoCSS之前,咱们先来了解几个闻名度高的同类思维CSS结构,热度比较高的有以下两种。

TailwindCSS

持续迭代,目前已发布3.0

闻名度最高的一款CSS结构,2.0版别增加了深色方法,JIT引擎(预先扫描源代码 ,按需编译一切CSS),比较传统的旧版别Tailwind,坚持了开发和出产环境的一致(旧版别运用开发环境未处理,生成的 CSS 文件会稀有 MB 的巨细,出产环境运用了PurgCSS删去未运用的CSS)

最新发布了3.0版别,默许开启JIT引擎(2.0需求手动开启)

Windi CSS

保护恐成难题

WindiCSS是以 TailwindCSS为创意制作的库,并且兼容了 TailwindCSS,零依赖,也不要求用户装置 PostCSS 和 Autoprefixer,供给了更快的加载时间和热更新,相同支撑按需生成,AntFu大佬在2021年的测验成果如下,HMR有100倍的效果。值得一提的是,WindCSS增加了特点方法,这意味着你能够以写特点的方法去写class名。

原子化CSS引擎UnoCSS

UnoCSS

Windi CSS现已满足优异,但Antfu依旧没有满意,结构预设外的自界说东西的额定装备依旧比较繁琐,不够灵敏;所以他从头构想了原子化CSS,UnoCSS得以诞生。

UnoCSS – 具有高性能且极具灵敏性的即时原子化 CSS 引擎。

之所以把它称作引擎,是因为没有像TailwindCSS,WindI CSS那样供给中心的应用程序,一切才能由预设供给,杰出中心:按需运用。

关于作者

闻名开源作者AntFu Github,Vite,Nuxt团队中心人员,Slidev作者

原子化CSS引擎UnoCSS

预设(presets)

unoCSS官方默许供给了三种预设

  1. @unoCSS/preset-uno 东西类预设

  2. @unoCSS/preset-attributify 特点化预设

  3. @unoCSS/preset-icons 图标类icon支撑

装置一波~

pnpm i -D unoCSS @unoCSS/preset-uno @unoCSS/preset-attributify @unoCSS/preset-icons

在vite.config.ts中引入,unoCSS作为插件在vite中运用

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import UnoCSS from 'unoCSS/vite'
import { presetUno, presetAttributify, presetIcons } from 'unoCSS'
import transformerDirective from "@unoCSS/transformer-directives";
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(),
  UnoCSS({
    presets: [presetUno(), presetAttributify(), presetIcons()],
    transformers: [transformerDirective()],
  })],
})

装置vscode插件,获得杰出的输入提示。

原子化CSS引擎UnoCSS

@unoCSS/preset-uno

这个预设供给了盛行的实用程序优先结构的通用超集,包含Tailwind CSS,Windi CSS,Bootstrap,Tachyons等

比如 ml-3(Tailwind),ms-2(Bootstrap),ma4(Tachyons),mt-10px(Windi CSS)

这些写法都会生效

<div w-20 h-20 bg-blue  ml-3 ms-2 ma4 mt-10px />

@unoCSS/preset-attributify

承继了WindiCSS的特点化方法,简化了书写class,以特点的方法去写class,但是在运用组件的时候,较大或许呈现特点太多,简单混杂的情况。

  <button
    bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"
    text="sm white"
  >
    Click
  </button>

@unoCSS/preset-icons

UnoCSS供给了图标的预设,它是纯CSS的图标,能够挑选Icones 或 Iconify作为图标源运用,相同也支撑自界说icon,本身完成按需加载。

  1. 装置
// 装置全部,大约140多M,开发时会装置,打包只会运用用到的图标
pnpm i -D @unoCSS/preset-icons @iconify-json
// 装置某个图标调集
pnpm i -D @unoCSS/preset-icons @iconify-json/icon调集id(例如icon-park-twotone)

icones.js.org/collection/… 中的 icon-park-twotone 即为这个Icon调集 id

原子化CSS引擎UnoCSS

  1. 运用

以Icones 调集为例,仿制i最初或许点击UnoCSS得到类名。

原子化CSS引擎UnoCSS

<div class="i-icon-park-twotone-winking-face"> </div>
  1. 多色图标

直接设置color值即可,特点化方法示例,color-blue

<div i-icon-park-twotone-winking-face colo text-size-100px  color-blue> </div>
  1. 额定特点

能够供给额定的 CSS 特点来控制图标的默许行为,默许情况下图标内联示例:

// vite.config.ts
presetIcons({
  extraProperties: {
    'display': 'inline-block',
    'vertical-align': 'middle',
    // ...
  },
})

更多检查github.com/unoCSS/unoC…

插件(plugins)

@unoCSS/transformer-directives

  • 官方供给了这个插件完成在style中运用apply指令写原子化CSS
...
export default defineConfig({
  plugins: [
    vue(),
    UnoCSS({
      ...
      transformers: [transformerDirective()]
    })
  ]
});

规矩(rules)

除了官方默许的东西类外,支撑自界说CSS规矩,装备rules数组即可,支撑方法1和方法2(正则匹配)两种。

// vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    UnoCSS({
      ...
      rules: [
        // 方法1
        [ 
          "p-a", 
          {  
            position: "absolute",
          }
        ],
        // 方法2
        [/^m-(d+)$/, ([, d]) => ({ margin: `${d / 4}px` })]
      ],
    })
  ]
});

项目中运用时会解析成对应的CSS款式,<div class="m-20"></div> 对应的style为

.m-20{
  margin : 5px;
}

值得一提,在装置了UnoCSS供给的VsCode插件后,这些自界说的部分相同会提示出来。

纯CSS图标

望文生义,不含有任何js元素,纯CSS完成。

现有计划

有个名为 css.gg 的纯 CSS 图标解决计划,它完全经过伪元素(::before::after)来构建图标,运用这种计划需求对CSS作业原理有着深刻理解。

UnoCSS中的计划

另一种计划,是将svg转换成dataurl,AntFu这里运用了Base64,并做了一系列优化,也便是说咱们看到的图标其实是图片,合作CSS的mask特点能够轻松完成多色图标。

原子化CSS引擎UnoCSS

  1. 处理svg字符串,转为dataurl
const dataUrl = `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`

svg本身是文本格式,转为Base64会变大,因而需求优化巨细。

  1. 优化-减小体积
// https://bl.ocks.org/jennyknuth/222825e315d45a738ed9d6e04c7a88d0
// https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
// 编码器
function encodeSvg(svg: string) {
    return svg.replace('<svg', (~svg.indexOf('xmlns') ? '<svg' : '<svg xmlns="http://www.w3.org/2000/svg"'))
      .replace(/"/g, ''')
      .replace(/%/g, '%25')
      .replace(/#/g, '%23')
      .replace(/{/g, '%7B')
      .replace(/}/g, '%7D')
      .replace(/</g, '%3C')
      .replace(/>/g, '%3E')
  }
  const dataUrl = `data:image/svg+xml;utf8,${encodeSvg(svg)}`       
  1. 输出成果:传入svg字符串运行encodesvg方法咱们会得到如下格式的url,最小编码的url诞生。
%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20d%3D%22M224%20387.814V512L32%20320l192-192v126.912C447.375%20260.152%20437.794%20103.016%20380.93%200%20521.287%20151.707%20491.48%20394.785%20224%20387.814z%22%2F%3E%3C%2Fsvg%3E

写在最后

比照TailWindCSS,UnoCSS或许显得并不是很鹤立鸡群,但它有着更小,更灵敏的优势;对一个开源项目来讲,开坑并不难,难的是保护,比照TailWindCSS一个公司级保护的项目,UnoCSS依旧有着很长的路要走。

参考资料

  1. 从头构想原子化CSS