每个前端人都经历过的一个痛处就是,在写页面 ui 样式时不停的在 html 文件(或代码区域)和 css 文件(或代码区域)之间来回切换,这种聚焦点分离让 ui 样式的开发有点点烦。原子化 css 正是这一痛处的有效的解决方案。

# 简介

原子化的优点也即原子化,因为所有书写的 css 都是以最原子的形态出现,所以可复用性无解肥。

原子化中每个 css 属性和值都有一个对应简写的 class 来实现,通常这些简写也符合认知规律,所以书写起来并没有很大心智负担,熟能生巧(唯手熟耳)。

这有点类似在 html 中书写 style,不过更加简单和快捷。比如:

  • w-10 就是 width: 100px
  • mx-10 就是 margin-left: 10px; margin-right: 10px;
  • last-mr-0 就是 :last-child { margin-right: 0; }

而且通过自定义规则配置,还能实现更多的简写,如:

  • wh-full 就是 width: 100%; height: 100%
  • bb-1-red 就是 border-bottom: 1px solid red;
  • f-b 就是 display: flex; justify-content: space-between; align-items: center;

在实际应用中代码如下:

<div class="inline-block h-164 bg-#F2F3F5 rounded-4 p-20 pt-16!">
    <div class="mb-8 text-14 text-#7A8699">示例(请按照示例上传真实、有效的集装箱照片):</div>
    <div class="f-s">
        <div class="relative w-100 h-100 mr-8 last-mr-0" v-for="item in sampleBoxPics" :key="item.id">
            <img class="wh-full object-cover" :src="`https://filecdn.xxx.com/xxx/box_pic_${item.id}.png`" alt="" />
            <div class="absolute bottom-0 w-full f-c bg-#1D2129/80 text-white text-12"></div>
        </div>
    </div>
</div>

# 安装配置(vue + vite 项目中):

安装 unocss 和工具类预设:

pnpm i -D unocss @unocss/preset-uno

在 main.ts 中引入 uno.css

import { createApp } from 'vue'
import App from './App.vue'
import 'virtual:uno.css'
createApp(App).mount('#app')

在 vite.config.ts 文件中配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import UnoCSS from 'unocss/vite'
export default defineConfig({
  plugins: [
    vue(),
    UnoCSS(),
  ],
  ...
})

新建 uno.config.ts 文件并配置(此处是我个人的配置偏好,可以根据喜好自己配置,或者根据项目需要配置一些常用公共样式):

// uno.config.ts
import { defineConfig, presetUno } from 'unocss'
import presetRemToPx from '@unocss/preset-rem-to-px'
export default defineConfig({
    presets: [
        presetUno(),
        //unocss 默认 rem,转成 px
        presetRemToPx({
            baseFontSize: 4,
        }) as any,
    ],
    shortcuts: {
        'f-b': 'flex justify-between items-center',
        'f-c': 'flex justify-center items-center',
        'f-s': 'flex justify-start items-center',
        'f-e': 'flex justify-end items-center',
        'text-overflow': 'truncate',
        'wh-full': 'w-full h-full',
    },
    rules: [
        [/^b-(\d+)$/, match => ({ 'border-width': `${match[1]}px` })],
        [/^b-(\d+)-#([\w]+)$/, match => ({ 'border': `solid ${match[1]}px #${match[2]}` })],
        [/^bt-(\d+)-#([\w]+)$/, match => ({ 'border-top': `solid ${match[1]}px #${match[2]}` })],
        [/^bb-(\d+)-#([\w]+)$/, match => ({ 'border-bottom': `solid ${match[1]}px #${match[2]}` })],
        [/^bl-(\d+)-#([\w]+)$/, match => ({ 'border-left': `solid ${match[1]}px #${match[2]}` })],
        [/^br-(\d+)-#([\w]+)$/, match => ({ 'border-right': `solid ${match[1]}px #${match[2]}` })],
        [/^px-(\d+)$/, match => ({ 'padding-left': `${match[1]}px`, 'padding-right': `${match[1]}px` })],
        [/^py-(\d+)$/, match => ({ 'padding-top': `${match[1]}px`, 'padding-bottom': `${match[1]}px` })],
        [/^mx-(\d+)$/, match => ({ 'margin-left': `${match[1]}px`, 'margin-right': `${match[1]}px` })],
        [/^my-(\d+)$/, match => ({ 'margin-top': `${match[1]}px`, 'margin-bottom': `${match[1]}px` })],
        [/^pt-(\d+)$/, match => ({ 'padding-top': `${match[1]}px` })],
        [/^pb-(\d+)$/, match => ({ 'padding-bottom': `${match[1]}px` })],
        [/^pl-(\d+)$/, match => ({ 'padding-left': `${match[1]}px` })],
        [/^pr-(\d+)$/, match => ({ 'padding-right': `${match[1]}px` })],
        [/^mt-(\d+)$/, match => ({ 'margin-top': `${match[1]}px` })],
        [/^mb-(\d+)$/, match => ({ 'margin-bottom': `${match[1]}px` })],
        [/^ml-(\d+)$/, match => ({ 'margin-left': `${match[1]}px` })],
        [/^mr-(\d+)$/, match => ({ 'margin-right': `${match[1]}px` })],
    ],
})

vscode 还有 UnoCSS 扩展,可以预览编译后的 class:

image.png

# 演练

有兴趣的少侠可以点击 此处 进行在线演练,零配置体验 unocss。

也可以在 这里 查看类名书写后编写的结果。

而我最常用的其实是 tailwindcss 文档,在这里可以查看各种 css 属性的书写方式(unocss 是兼容 tailwindcss 的,而 unocss 官网貌似并没有提供此类文档)。

# 缺点

原子化 css 在编写复杂的样式效果时,会造成 html 的 class 名非常长,而且 vue react 等框架中,都会有部分 js 逻辑注入 html 中,这样 html 文件会变得臃肿不堪。

原子化 css 违背了组件化的设计思想,比如你用 unocss 写了一个组件,后来发现比较通用想发包就比较麻烦了。

维护项目时,不再可以通过 css 名来定位代码位置,接手陌生项目时会比较痛苦。

# 最后

虽然存在很多问题,但是原子化带来的好处是无可比拟的。而且他让你的项目避免了很多重复混乱的 css 命名。