Vue + UnoCSS 避免影响全局样式

Vue + UnoCSS 避免影响全局样式
狂犬主子Vue + UnoCSS 避免影响全局样式
最近尝试使用 Vite 将一个 Vue 3 组件打包成 JS,以便插入一个不是 Vue 写的 HTML 中。本人属于前端小白,不会写CSS。由于 AI 写这种类名样式比较厉害,且听说 UnoCSS 比较厉害,故使用 UnoCSS + presetWind4 的方案。
不过实际部署后发现一个严重的问题,由于缺少隔离机制,UnoCSS / Tailwind CSS 会导致全局样式被覆盖,表现为外部的原生样式丢失。为了避免造成更大的影响,需要对其进行处理,避免全局样式被影响。
尝试 vue-scoped 模式
经过阅读 UnoCSS 文档,发现其支持vue-scoped功能,感觉可以完美解决这个问题,将样式限制到 Vue 的 <style scope> 内:
https://unocss.dev/integrations/vite#modes
Modes
The Vite plugin comes with a set of modes that enable different behaviors.
global(default)This is the default mode for the plugin: in this mode you need to add the import of
uno.csson your entry point.This mode enables a set of Vite plugins for
buildand fordevwithHMRsupport.The generated
csswill be a global stylesheet injected on theindex.html.
vue-scopedThis mode will inject generated CSS to Vue SFCs
<style scoped>for isolation.
具体使用方法:
1 | import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import { resolve } from "path"; import UnoCSS from "unocss/vite"; export default defineConfig({ plugins: [vue(), UnoCSS({ mode: "vue-scoped", })], ... }); |
但经过实测发现样式只正常一半,和 Tailwind CSS 基本一样,经过查找发现这给问题还没修复。
- Issue:[presetWind4] Missing CSS variables in vue-scoped mode · Issue #4825 · unocss/unocss
- PR:fix(vite): styles missing or duplicated when mode is
vue-scopedby Jungzl · Pull Request #4829 · unocss/unocss
这个 PR 已经无法跟上最新版本,所以这招暂时行不通,否则应该是最优解。
Tailwind CSS 完整用法
这个时候感觉到 UnoCSS 存在问题,又换回 Tailwind CSS,发现其存在一个 preflight 机制(https://tailwindcss.com/docs/preflight):简单来说就是给浏览器的那些自带样式清空。
正常情况下,我们用 Tailwind CSS v4,只需要在 CSS 里面引入一句:
1 | @import "tailwindcss"; |
实际上里面包含了:
1 | @layer theme, base, components, utilities; @import "tailwindcss/theme.css" layer(theme); @import "tailwindcss/preflight.css" layer(base); @import "tailwindcss/utilities.css" layer(utilities); |
这个 @layer 是什么意思呢?查询 MDN 发现,这是一个样式作用的过程,相当于不同的优先级,相当于定义CSS的作用域。
我可以给我的 Vue 组件加个 id,然后用这玩意限定一下清理的范围即可。
1 | @layer theme, base, components, utilities; @import "tailwindcss/theme.css" layer(theme); #extension-root { @import "tailwindcss/preflight.css" layer(base); } @import "tailwindcss/utilities.css" layer(utilities); |
(来自:https://j5cookie.medium.com/scoping-tailwindcss-preflight-for-injected-apps-c30152f6dd8d)
但是,经过实测,这样在 Vue Scope 内并不好使,样式还是存在小问题。
回归 UnoCSS
基于上面对 Tailwind CSS 的了解,继续看回 UnoCSS 的文档,发现 UnoCSS 的 presetWind4 支持开关 Reset 样式,貌似找到了希望,紧接着还发现其支持合并+随机类名,这样可以解决冲突的问题,那就不得不用 UnoCSS 了。
比如:
1 | <div class=":uno: text-center sm:text-left"> <div class=":uno: text-sm font-bold hover:text-red" /> </div> |
会合并成:
1 | <div class="uno-qlmcrp"> <div class="uno-0qw2gr" /> </div> |
通过这种合并,可以避免污染外部环境,实现“隔离”的效果。但此时 Reset 样式还没解决。
使用 Vue <style scope> 解决 Reset 样式污染
首先去到 uno.config.js/ts 里面 reset: false,然后在对应的 Vue 组件里面手动导入 @unocss/reset/tailwind-v4.css,结果样式出现了部分泄露,通过对其 @layer 进行限制,即可解决这个问题。
经过测试,外部样式几乎未受影响,组件内部样式没有问题。
完整配置
vite.config.js
1 | import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import { resolve } from "path"; import UnoCSS from "unocss/vite"; export default defineConfig({ plugins: [vue(), UnoCSS()], define: { "process.env": JSON.stringify({ NODE_ENV: process.env.NODE_ENV || "production", }), }, build: { lib: { entry: resolve(__dirname, "src/main.js"), name: "VueApp", fileName: (format) => `vue-app.${format}.js`, formats: ["umd"], }, cssCodeSplit: true, }, }); |
uno.config.js
1 | import { defineConfig, presetWind4, transformerCompileClass } from "unocss"; export default defineConfig({ content: { pipeline: { include: [/\.(vue)($|\?)/], }, }, presets: [ presetWind4({ preflights: { reset: false, }, }), ], transformers: [ transformerCompileClass({ classPrefix: "vapp-", }), ], }); |
src/App.vue
1 | <script setup> import "virtual:uno.css"; </script> <html> <div class="flex items-center justify-center min-h-screen bg-gray-100 "> <button class="p-2 bg-green-600 hover:bg-green-700 text-white rounded-lg shadow-md transition-all" > UnoCSS </button> </div> </html> <style scoped> @layer base; @import "@unocss/reset/tailwind-v4.css" layer(base); </style> |
最后
Vue 牛逼!!!UnoCSS 牛逼!!!antfu 神!!!



