跳到主要内容

uni-app Vite App WebView 中特殊字符类名的支持结论

结论先说清楚:普通 uni-app Vite 运行到 Android / iOS App WebView 后,WebView 的 DOM/CSSOM 本身并不是完全不支持 dark:bg-red-300text-[45rpx] 这类带 :[] 的 class。只要 class 原样进入 DOM,并且 CSS selector 做了标准 CSS 转义,例如 .dark\:bg-red-300.text-\[45rpx\],真实 WebView 可以匹配到样式。

但在 uni-app Vite + Tailwind CSS + weapp-tailwindcss 的实际构建链里,不建议依赖这些 raw class 留在最终 App 产物中。原因是 App 端还要同时处理:

  • Vue / uni-app 模板编译后的运行时代码
  • Tailwind v4 生成的 selector 与变体 selector
  • rpx 任意值的长度单位归类与单位转换
  • Android / iOS WebView 对现代 CSS 值的兼容差异
  • JS 字符串 class 与 CSS selector 是否一一对应

因此 weapp-tailwindcss 在普通 uni-app App WebView 分支会把这些类名映射成 safe class,并让 JS 运行时代码和 CSS selector 同步。例如:

源码写法App WebView 产物 class
dark:bg-red-300dark_cbg-red-300
text-[45rpx]text-_b45rpx_B
bg-white/70bg-white_f70

本次验证环境

demo/uni-app-vite-tailwindcss-v4 已分别运行到 Android 和 iOS App,并确认输出目录为 dist/dev/app-plus

平台运行时WebView 版本信息验证结论
AndroidHBuilder 15.07 / 1507,Android 11 emulatorAndroid System WebView com.google.android.webview 91.0.4472.114,UA 中 Chrome/91.0.4472.114AppleWebKit/537.36raw class selector、raw class 属性选择器、safe class 均匹配
iOSHBuilder 15.07 / 1507,iOS Simulator 26.5WKWebView / WebKit bundle 8624.2.5.10.4,Safari 26.5 / 8624.2.5.10.4view 层 raw class 属性选择器、safe class 均匹配

Android 通过 WebView 远程调试协议在真实 HBuilder App WebView 中执行 DOM/CSSOM 探针,结果为:

{
"rawClassSelectorMatched": true,
"rawAttributeSelectorMatched": true,
"rawTextClassSelectorMatched": true,
"rawTextAttributeSelectorMatched": true,
"safeDarkMatched": true,
"safeTextMatched": true
}

iOS 的 uni-app App service 层不一定暴露 document,所以页面上的 DOM/CSSOM 探针会显示 document unavailable。因此 iOS 同时提供 Special Class Visual Probe 可视探针:它把 raw class 通过运行时拼接绑定到 view/text,再用 [class~="dark:bg-red-300"][class~="text-[45rpx]"] 这类属性选择器匹配。iOS 截图中 raw dark 背景变粉、raw text 变为 45px,说明 view 层可以保留并匹配这些 raw class。

验证方式

仓库里的 demo/uni-app-vite-tailwindcss-v4 首页包含一个 Special Class Probe 面板。把它运行到 Android 或 iOS App 后,会在真实 App WebView 中执行下列检查:

  1. document.createElement 创建 raw class 元素:
    • dark:bg-red-300
    • text-[45rpx]
  2. 注入标准转义后的 CSS selector:
    • .dark .dark\:bg-red-300
    • .text-\[45rpx\]
  3. 创建 safe class 对照组:
    • dark_cbg-red-300
    • text-_b45rpx_B
  4. 使用 getComputedStyle 读取真实渲染结果。

页面和 console 会输出:

[uni-app-vite] Special Class Probe

如果看到:

raw.dark:bg-red-300.matched: true
raw.text-[45rpx].matchedViaEscapedSelector: true
safe.dark_cbg-red-300.matched: true
safe.text-_b45rpx_B.matched: true

说明当前可运行 DOM/CSSOM 探针的 App WebView 本身可以识别这些 raw class,只是要求 CSS selector 正确转义。iOS 如果显示 document unavailable,以页面里的 Special Class Visual Probe 为准。

页面还包含 Special Class Visual Probe。它不依赖 document,用于覆盖 iOS 这类 service 层没有 DOM API 的 App 运行时。该探针包含两组对照:

  • raw 组:运行时拼接出 dark:bg-red-300text-[45rpx] 并绑定到页面节点。
  • safe 组:直接使用 dark_cbg-red-300text-_b45rpx_B

如果 raw 组和 safe 组都出现粉色背景、45px 大字,说明当前 App view 层可以保留并匹配 raw class;如果只有 safe 组命中,则说明不能依赖 raw class 直接进入最终产物。

推荐写法

业务源码继续写 Tailwind 原始类名:

<view class="theme-dark dark:bg-red-300 text-[45rpx]">
App WebView
</view>

不要手写产物里的 safe class,也不要在业务代码里混用 raw class 和 safe class。safe class 是构建产物契约,由 weapp-tailwindcss 负责生成和同步。

不推荐的做法

不要通过关闭 weapp-tailwindcss 或跳过转译来强行保留 raw class:

// 不推荐:App WebView 下容易造成 CSS selector、JS class 与 rpx 处理不一致
WeappTailwindcss({
disabled: process.env.UNI_PLATFORM === 'app',
})

普通 uni-app App WebView 应继续保留插件,让生成器按 WebView 分支输出兼容 CSS。

排查标准

如果 App 端看到这类样式不生效,优先按下面顺序查:

  1. 看最终 dist/dev/app-plus/app-service.js 里的 class 是否已经变成 safe class。
  2. 看最终 dist/dev/app-plus/app.css 是否存在对应 safe selector。
  3. 看颜色是否已经从 Tailwind v4 的 oklch() / color-mix() 降级为 rgb()rgba()#hex
  4. text-[45rpx] 是否生成了长度样式,而不是错误地生成 color: 45rpx
  5. 再看 Special Class Probe 面板,区分“WebView 本身不支持 raw class”还是“构建链没有把 class 和 CSS 对齐”。

当前结论

基于 demo/uni-app-vite-tailwindcss-v4 在 Android / iOS App WebView 上的实测,结论是:

  • :[] 这类特殊字符不是 App WebView 的绝对禁区。
  • raw class 只有在 DOM class 与转义后的 CSS selector 同时保留时才可靠。
  • iOS App service 层可能没有 document,不要把 document.createElement 探针是否可运行等同于 view 层是否支持特殊 class。
  • 在真实 uni-app Vite + Tailwind CSS 产物中,更稳定的方案是使用 weapp-tailwindcss 自动输出 safe class。
  • 文档、demo 与测试都应按 safe class 作为最终产物断言,而不是假设 raw class 会保留到 App 产物。