基于vanilla-extract-css的Vue3 css modules方案

avatar

背景

一个现有的vue3项目,使用的是tsx,因为没有使用sfc,因此<style module>也无法使用。目前的方案是通过引入scss文件来进行样式处理,这样就会导致样式都是全局的,无法对样式进行scope,所以想要探索vue3 tsx的css modules方案。

在网上搜索了很长时间都没有到一个合适的方案,最后无意间在一个开源项目中发现他们使用的是@vanilla-extract/css,研究了一下发现在项目中正好可以使用。

vanilla-extract-css是什么

Write your styles in TypeScript (or JavaScript) with locally scoped class names and CSS Variables, then generate static CSS files at build time.
Basically, it’s “CSS Modules-in-TypeScript” but with scoped CSS Variables + heaps more.

一言以概之,就是用ts来写css moudles。

配置

vanilla-extract-c的配置非常简单,首先安装依赖。(相关代码都上传到了github上 vue3-css-modules)

npm install @vanilla-extract/css

根据打包器安装不同的plugin
image.png
我使用的是vite,安装配置如下

npm install --save-dev @vanilla-extract/vite-plugin
import { fileURLToPath, URL } from 'node:url'
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
    plugins: [vue(), vueJsx(), vanillaExtractPlugin({})],
    resolve: {
        alias: {
            '@': fileURLToPath(new URL('./src', import.meta.url))
        }
    }
})

使用

css属性

    export const myHeader = style({
      fontSize: '16px',
      fontWeight: 700,
      lineHeight: 1.2,
      color: 'yellow'
    })

    import { defineComponent } from 'vue'
    import { myHeader } from '../styles/app.css'

    export default defineComponent({
      name: 'HomeView',
      setup() {
        return () => (
          <>
            <header class={myHeader}>my header</header>
          </>
        )
      }
    })

经过编译后的样式,如下 image.png

主题和变量

// 主题和变量
export const [themeClass, vars] = createTheme({
  color: {
    brand: 'blue',
    text: 'red'
  },
  font: {
    body: 'arial'
  }
})

export const label = style({
  color: vars.color.text,
  // 伪类选择器
  ':hover': {
    color: 'white'
  }
})

import { defineComponent } from 'vue'
import { myHeader, themeClass, label } from '../styles/app.css'

export default defineComponent({
  name: 'HomeView',
  setup() {
    return () => (
      <>
        <header class={myHeader}>my header</header>
        <div class={themeClass}>
          <span class={label}>my label</span>
        </div>
      </>
    )
  }
})

image.png

全局样式

// 全局样式
globalStyle('body', {
  background: 'darkgray'
})

样式组合

// 样式组合
export const base = style({ padding: 12 })

export const primary = style([base, { background: vars.color.brand }])

export const secondary = style([base, { background: 'aqua' }])

image.png

总结

总结一下,@vanilla-extract/css 是一个用于在 TypeScript 和 JavaScript 中编写类型安全的 CSS 的库,它可以与 Vue 3 的 TSX 结合使用,提供了 CSS Modules 的功能。 使用 @vanilla-extract/css,你可以:

  • 定义样式属性并将其应用于组件中的元素。
  • 使用普通的 CSS 属性,如字体大小、颜色等。
  • 使用变量和主题来定义样式,使样式更加灵活和可配置。
  • 创建全局样式,对整个应用生效。
  • 定义样式组合,将多个样式组合在一起使用。

这些功能可以让你在 Vue 3 TSX 项目中实现样式的模块化和作用域化,提高样式的可维护性和可扩展性。