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.vue → ComponentA.wxss
    • ComponentB.vue → ComponentB.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:使用 px、rem、em
  • 小程序:使用 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:避免开发模式的兼容性问题
相关推荐
FX1317887KP_1 小时前
PET口语备考攻略:发音、语法、表达,三个问题怎么同时解决
小程序·ket口语·pet口语·fce备考·剑桥英语
地球@+jdhb441 小时前
企业私域运营新趋势:快手短视频平台跳转小程序企微卡片链路搭建成为商家运营重点
小程序·企业微信
程序鉴定师2 小时前
2026年深圳小程序/App开发公司技术选型指南:从架构设计到交付标准全维度评估
java·小程序·uni-app·php·objective-c
Q26433650233 小时前
【有源码】基于uni-app的旅游行程规划小程序-基于微信小程序的智慧文旅综合服务平台
java·微信小程序·小程序·uni-app·毕业设计·springboot·源代码
网硕互联的小客服5 小时前
微信小程序多种跳转页面方式教学
微信小程序·小程序·notepad++
m0_5873830019 小时前
24小时自助健身房软硬件解决方案实战指南:从架构设计到部署实施
java·spring·小程序·架构·需求分析
m0_587383001 天前
24小时自助健身房软硬件解决方案实战:从架构设计到部署指南
java·spring·小程序·架构·需求分析
CRMEB系统商城1 天前
前后端技术栈全面换代!CRMEB 多商户(Java)v3.0更新预告
java·开发语言·小程序·php
2501_916007471 天前
苹果应用商店App Store上架费用标准及原因解析
android·ios·小程序·https·uni-app·iphone·webview
00后程序员张2 天前
苹果App Store上架指南:费用、原理与步骤详解
android·ios·小程序·https·uni-app·iphone·webview