摘要:当用户将手机系统设置为"深色模式"打开应用时,应用先是闪过一道刺眼的白光,然后才变黑。这种"闪白"现象是混合开发中常见的体验杀手。本文介绍了如何打通 HarmonyOS 原生与 Web 的深色模式配置,实现毫秒级的同步切换。

👻 1. 幽灵闪白

现象复现:

  1. 系统设置 -> 显示和亮度 -> 选择"深色模式"。
  2. 冷启动我们的 Cordova 应用。
  3. 闪烁:屏幕白屏约 0.5s -> 加载 CSS -> 变为深色。

这 0.5s 的白屏对于夜间使用的用户来说,简直是"闪光弹"攻击。

🔬 2. 原因分析

Web 页面的深色模式适配通常依赖 CSS 媒体查询:

@media (prefers-color-scheme: dark) {
    body { background-color: #121212; color: #fff; }
}

问题的根源在于时序

  1. Native 启动(Native 背景默认可能是白色)。
  2. Webview 初始化(Webview 默认底色是白色)。
  3. 加载 HTML/CSS。
  4. 解析 prefers-color-scheme,应用深色样式。

在步骤 2 和 3 之间,用户看到的就是默认的白色背景。

🛠️ 3. 解决方案

我们需要从 Native 到 Web 全链路同步颜色配置。

3.1 第一步:Native 背景色同步

在 ArkWeb 组件加载出页面内容之前,它本身只是一个原生的 View。我们需要先把它涂黑。

EntryAbility.ets 或页面 Index.ets 中,根据系统配置设置背景色。

import configuration from '@ohos.app.ability.Configuration';

@Entry
@Component
struct Index {
  @State isDarkMode: boolean = false;

  aboutToAppear() {
    // 获取当前系统颜色模式
    const context = getContext(this);
    const config = context.config;
    this.isDarkMode = config.colorMode === configuration.ColorMode.COLOR_MODE_DARK;
  }

  build() {
    Column() {
      Web({ src: '...', controller: this.controller })
        .backgroundColor(this.isDarkMode ? '#121212' : '#FFFFFF') // 关键:设置 Web 组件底色
        .darkMode(WebDarkMode.Auto) // 启用 Webview 的暗黑模式支持
        .forceDarkAccess(true) // 强制允许网页访问深色模式
    }
    .backgroundColor(this.isDarkMode ? '#121212' : '#FFFFFF') // 设置容器底色
  }
}

3.2 第二步:监听系统切换

用户可能在使用过程中切换模式。我们需要监听 onConfigurationUpdate

// EntryAbility.ets
onConfigurationUpdate(newConfig: Configuration) {
    const colorMode = newConfig.colorMode;
    // 通过 EventHub 或全局状态通知 UI 更新
    AppStorage.SetOrCreate('currentColorMode', colorMode);
}

3.3 第三步:Web 侧的即时响应

虽然 CSS prefers-color-scheme 能自动响应,但有时候我们需要 JS 知道当前模式(比如切换 Canvas 绘图颜色或 ECharts 主题)。

我们可以在 index.html 头部注入一段 JS,防止 CSS 加载延迟导致的闪烁。

<head>
    <script>
        // 立即执行,在 body 渲染前决定 class
        if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
            document.documentElement.classList.add('dark-mode');
        }
        
        // 监听变化
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
            if (event.matches) {
                document.documentElement.classList.add('dark-mode');
            } else {
                document.documentElement.classList.remove('dark-mode');
            }
        });
    </script>
    <style>
        /* 默认样式 */
        html { background: #fff; }
        
        /* 配合脚本的样式,优先级更高 */
        html.dark-mode { background: #121212; }
        
        /* 标准媒体查询作为兜底 */
        @media (prefers-color-scheme: dark) {
            html { background: #121212; }
        }
    </style>
</head>

🎨 4. 进阶:强制覆盖 (Force Dark)

鸿蒙 ArkWeb 提供了一个强大的 API:.forceDarkAccess(true)
如果你的老旧网页完全没有适配深色模式(全是写死的 background: white),这个 API 会让浏览器内核自动通过算法将页面反色。

优点:一键适配老旧页面。
缺点:图片和视频可能会色彩失真。

对于精细化开发的 App,建议关闭 Force Dark 或仅作为保底手段,优先使用 CSS 自定义适配。

📜 5. 总结

消除"闪白"的核心在于预判

  1. Native 层:在 Web 加载前,就把容器背景设为黑色。
  2. Web 层:在 Head 脚本中立即应用深色 Class,不要等待外部 CSS 文件加载。
  3. 联动层:利用 ArkWeb 的配置接口,打通系统与内核的配置通道。

现在的应用启动过程:
用户点击 -> 黑色 Native 背景 -> 黑色 Webview 容器 -> 黑色 H5 页面。
如丝般顺滑,再也不伤眼了。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐