UnoCSS 集成指南 - 小程序适配原理

文章目录

  • 前言
  • [UnoCSS 集成指南 - 小程序适配原理](#UnoCSS 集成指南 - 小程序适配原理)
    • 问题背景
    • [核心问题:小程序与 Web 的架构差异](#核心问题:小程序与 Web 的架构差异)
      • [1. 样式隔离机制不同](#1. 样式隔离机制不同)
      • [2. UnoCSS 默认工作模式](#2. UnoCSS 默认工作模式)
    • 解决方案原理
      • [1. 使用 `per-module` 模式](#1. 使用 per-module 模式)
      • [2. 插件顺序:uni() 必须在前](#2. 插件顺序:uni() 必须在前)
      • [3. presetUni() 预设](#3. presetUni() 预设)
        • [a. 单位转换](#a. 单位转换)
        • [b. 样式兼容性处理](#b. 样式兼容性处理)
        • [c. 平台差异抹平](#c. 平台差异抹平)
      • [4. envMode: 'build' 配置](#4. envMode: 'build' 配置)
    • 完整的样式生成流程
    • 实际配置
      • [1. main.ts - 移除条件编译](#1. main.ts - 移除条件编译)
      • [2. vite.config.ts](#2. vite.config.ts)
      • [3. uno.config.ts](#3. uno.config.ts)
    • 验证结果
    • 依赖版本
    • 总结

前言

UnoCSS 集成指南 - 小程序适配原理

问题背景

在 uni-app 项目中集成 UnoCSS 后,H5 端样式正常显示,但小程序端样式完全加载失败。

核心问题:小程序与 Web 的架构差异

1. 样式隔离机制不同

Web (H5)

  • 全局样式表:所有样式可以写在一个 CSS 文件中
  • 样式作用域:通过 CSS 选择器控制
  • 动态注入:支持运行时动态插入 <style> 标签

小程序

  • 组件样式隔离:每个组件必须有独立的 .wxss 文件
  • 页面样式隔离:每个页面必须有独立的 .wxss 文件
  • 静态编译:不支持运行时动态注入样式
  • 样式文件必须在编译时确定

2. UnoCSS 默认工作模式

UnoCSS 默认采用 全局模式 (global mode)

  • 扫描所有源码,收集所有使用的原子类
  • 生成一个统一的 uno.css 文件
  • 在入口文件导入这个全局样式表

这种模式在 Web 环境完美运行,但在小程序中会失败,因为:

  • 小程序不支持全局样式表
  • 每个组件/页面需要独立的样式文件
  • 样式必须在编译时静态生成

解决方案原理

1. 使用 per-module 模式

typescript 复制代码
UnoCSS({
  mode: 'per-module'  // 关键配置
})

原理

  • 全局模式 (global) :生成一个 uno.css 包含所有样式
  • per-module 模式 :为每个 Vue 组件单独生成样式
    • ComponentA.vueComponentA.wxss
    • ComponentB.vueComponentB.wxss
    • 每个组件只包含自己使用的原子类

为什么这样能解决问题

  • 符合小程序的组件样式隔离机制
  • uni-app 编译器会将每个组件的样式提取到对应的 .wxss 文件
  • 避免了全局样式表的依赖

2. 插件顺序:uni() 必须在前

typescript 复制代码
plugins: [
  uni(),      // 必须在前
  UnoCSS(),   // 必须在后
]

原理

  • uni() 插件:负责将 Vue SFC 转换为小程序组件

    • 解析 .vue 文件
    • 提取 <template>.wxml
    • 提取 <script>.js
    • 提取 <style>.wxss
  • UnoCSS 插件:负责生成原子 CSS

    • 扫描模板中的 class
    • 生成对应的 CSS 规则
    • 注入到组件的 <style>

为什么顺序重要

  1. uni() 先处理:识别 uni-app 特有语法和组件结构
  2. UnoCSS 后处理:在 uni() 转换后的基础上注入样式
  3. 如果顺序反了:UnoCSS 无法正确识别小程序组件结构

3. presetUni() 预设

typescript 复制代码
presets: [
  presetUni(),  // uni-app 专用预设
]

@uni-helper/unocss-preset-uni 解决的问题

a. 单位转换
  • Web:使用 pxremem
  • 小程序:使用 rpx(响应式像素)
  • presetUni 自动将 UnoCSS 的单位转换为 rpx
typescript 复制代码
// 你写的代码
<view class="w-100 h-50">

// presetUni 转换后
.w-100 { width: 100rpx; }  // 不是 100px
.h-50 { height: 50rpx; }
b. 样式兼容性处理
  • 过滤小程序不支持的 CSS 属性
  • 转换小程序特有的样式写法
  • 处理伪类和伪元素的兼容性
c. 平台差异抹平
typescript 复制代码
// 某些 CSS 特性在小程序中不支持
backdrop-filter  // 部分小程序不支持
position: sticky // 小程序支持有限

presetUni 会自动处理这些差异。

4. envMode: 'build' 配置

typescript 复制代码
envMode: 'build'

原理

  • 开发模式 (dev):UnoCSS 会进行热更新检查、样式预检查
  • 构建模式 (build):跳过开发时的检查,直接生成最终样式

为什么小程序需要这个

  • 小程序的开发模式与 Web 不同
  • 开发时的预检查可能误判小程序环境
  • 强制使用构建模式避免兼容性问题

完整的样式生成流程

H5 模式

复制代码
源码 → UnoCSS 扫描 → 生成 uno.css → 全局导入 → 浏览器渲染

小程序模式(正确配置后)

复制代码
源码 → uni() 解析组件
     ↓
     UnoCSS (per-module) 为每个组件生成样式
     ↓
     ComponentA.vue → ComponentA.wxss
     ComponentB.vue → ComponentB.wxss
     ↓
     小程序运行时加载独立样式文件

实际配置

1. main.ts - 移除条件编译

typescript 复制代码
// ❌ 错误:排除小程序
// #ifndef MP-WEIXIN
import "uno.css";
// #endif

// ✅ 正确:所有平台都导入
import "uno.css";

原因 :per-module 模式下,uno.css 只是一个入口标识,实际样式已经分散到各个组件中。

2. vite.config.ts

typescript 复制代码
export default defineConfig(async () => {
  const UnoCSS = await import("unocss/vite").then((m) => m.default);
  
  return {
    plugins: [
      uni(),      // 1. 先处理 uni-app 转换
      UnoCSS({
        mode: 'per-module'  // 2. 按组件生成样式
      }),
    ],
  };
});

3. uno.config.ts

typescript 复制代码
export default defineConfig({
  presets: [
    presetUni(),        // uni-app 适配
    presetAttributify(), // 属性化模式
    presetIcons(),      // 图标支持
  ],
  transformers: [
    transformerDirectives(),      // @apply 等指令
    transformerVariantGroup(),    // 变体组语法
  ],
  envMode: 'build',  // 强制构建模式
});

验证结果

配置正确后,编译输出:

复制代码
dist/dev/mp-weixin/
├── components/
│   ├── AudioPlayer.wxss    ← 独立样式
│   ├── ModeSelector.wxss   ← 独立样式
├── pages/
│   ├── practice/
│   │   └── practice.wxss   ← 独立样式

每个 .wxss 文件只包含该组件使用的原子类,实现了样式隔离。

依赖版本

json 复制代码
{
  "unocss": "^66.5.10",
  "@uni-helper/unocss-preset-uni": "^0.2.11",
  "@dcloudio/vite-plugin-uni": "3.0.0-4080420251103001"
}

总结

小程序集成 UnoCSS 的核心是理解:

  1. 架构差异:小程序需要组件级样式隔离
  2. per-module 模式:让 UnoCSS 适配小程序的样式机制
  3. 插件顺序:确保 uni-app 编译流程正确
  4. presetUni:处理单位转换和平台兼容性
  5. envMode:避免开发模式的兼容性问题
相关推荐
李慕婉学姐5 小时前
基于微信小程序的运动会信息管理系统k6kqgy34(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·微信小程序·小程序
风月歌5 小时前
小程序项目之驾校报名小程序源代码(java+vue+小程序+mysql)
java·vue.js·mysql·小程序·毕业设计·源码
风月歌5 小时前
小程序项目之使命召唤游戏助手源代码(java+vue+小程序+mysql)
java·mysql·小程序·毕业设计·源码
小码哥0685 小时前
家政服务管理系统(源码+文档+部署+讲解)
小程序·家政系统·家政服务系统·家政服务管理系统
星光一影1 天前
美容/心理咨询/问诊/法律咨询/牙医预约/线上线下预约/牙医行业通用医疗预约咨询小程序
mysql·小程序·vue·php·uniapp
游戏开发爱好者81 天前
H5 混合应用加密 Web 资源暴露到 IPA 层防护的完整技术方案
android·前端·ios·小程序·uni-app·iphone·webview
2501_915106321 天前
最新版本iOS系统设备管理功能全面指南
android·macos·ios·小程序·uni-app·cocoa·iphone
游戏开发爱好者81 天前
HTTPS DDoS 排查 异常流量到抓包分析
网络协议·ios·小程序·https·uni-app·iphone·ddos
jay神1 天前
【原创】基于小程序的图书馆座位预约系统
微信小程序·小程序·毕业设计·图书馆自习室座位预约系统·座位预约系统