前端主题切换方案

前言

本文介绍前端主题切换的常见解决方案。

分两个部分:

    1. 需要考虑浏览器兼容性的场景(例如H5页面的开发);
    1. 无需考虑浏览器兼容性的场景。

这两个部分差异较大,针对场景1,笔者采用的是名为css-vars-ponyfill的第三方库(补丁),针对场景2,笔者则是完全依靠css完成主题切换的功能。

需要考虑浏览器兼容性的场景

1. 安装css-vars-ponyfill

shell 复制代码
yarn add css-vars-ponyfill

2. 获取当前主题token

对于h5页面的开发,一般来说都是从客户端的cookie中获取当前主题字段的,如下所示:

js 复制代码
const theme = getCookie("themeMode");

上面的getCookie函数作用为:从cookie中获取对应key的value, 详见[getCookie](解读JavaScript中cookie操作函数getCookie的实现原理和应用场景 - 掘金 (juejin.cn))

3. 根据当前的主题返回css键值对

构造一个名为getThemeVars的函数,其入参就是刚从cookie中获取的主题,返回值为类似于下的键值对:

js 复制代码
{
  ...,
  "--hc-primary-color": "#2b3c4d",
}

4. 构造initTheme函数,初始化css变量

js 复制代码
import cssVars from "css-vars-ponyfill";
...
export function initTheme() {
	cssVars({
		rootElement: document,
		variables: getThemeVars(),
		shadowDOM: false,
		include: 'link[rel=stylesheet],style',
		onFinally: function(hasChanged, hasNativeSupport, benchmark) {
			console.log('onFinally', hasChanged, hasNativeSupport, benchmark)
		}
	})
}

这段代码的作用是使用 "css-vars-ponyfill" 库来初始化主题。

首先 ,通过 import cssVars from "css-vars-ponyfill" 的语句导入了 "css-vars-ponyfill" 库。

然后 ,定义了一个名为 initTheme 的函数,用于初始化主题。在函数内部,调用了 cssVars() 方法,并传入一些配置选项对象。

配置选项的含义如下:

  • rootElement: document:设置根元素为整个文档(document 对象)。
  • variables: getThemeVars():设置 CSS 变量的值,getThemeVars() 是一个函数,用于获取 CSS 变量的值。
  • shadowDOM: false:指定是否处理 Shadow DOM 附件中的样式,默认为 false。
  • include: 'link[rel=stylesheet],style':设置引入 CSS 的方式,通过选择器指定要包含的 <link rel="stylesheet"><style> 元素。
  • onFinally: function(hasChanged, hasNativeSupport, benchmark) {...}:在最终处理完成后触发的回调函数,其中 hasChanged 表示 CSS 变量是否有变化,hasNativeSupport 表示浏览器是否原生支持 CSS 变量,benchmark 表示处理所花费的时间。

最后 ,在 onFinally 的回调函数中使用 console.log() 打印出 hasChangedhasNativeSupportbenchmark 的值。

通过这段代码,可以实现在旧版浏览器中使用 CSS 变量的功能,并根据需要进行自定义配置。该代码将应用指定的 CSS 变量值,并在完成处理后进行回调。

5. 初始化主题颜色

以React项目创建的H5页面被客户端调用为例:

在整个项目的入口文件App.tsx中,直接调用initTheme方法即可。这一块的逻辑可以表示如下图:

无需考虑浏览器兼容性的场景(参考渡一教育)

如果使用的浏览器支持最新的CSS变量语法,那么只需要通过修改适配在html元素上的css变量的值就可以了。

1. 在全局样式文件中构建不同主题下css变量的值

项目的主题设置在全局样式文件中,一般是index.css

css 复制代码
:root {
  --text-color: #fff;
  --bg1: #102128;
  --bg2: #2d5567;
}

html[data-theme='dark'] {
  --text-color: #333;
  --bg1: #c7ffdd;
  --bg2: #fbd988;
}


.btn {
  color: var(--text-color);
  background-color: var(--bg1);
}

这里必须 保证html[data-theme='dark']的权重大于:root.

2. 在项目的入口js文件中引入全局css文件

js 复制代码
import 'src/index.css';

3. 提供主题的全局控制函数

一般来说,全局函数会放在项目的src/utils/index.js文件中:

js 复制代码
let theme = 'light';
export const getTheme = () => theme;
export const setTheme = (_theme) => void theme = _theme;

这样通过调用getTheme或者setTheme函数就可以获取、设置theme的值了。

4. getTheme的使用场景

假设这样的场景,如果主题是夜晚就在页面的右上角显示"夜晚, 漆黑的夜晚..."这个文案;而主题如果是白天就显示"白昼, 热烈的阳光..."

html 复制代码
import { getTheme } from 'src/utils/index.js';
<span>{getTheme()==='light' ? '白昼, 热烈的阳光...' : '夜晚, 漆黑的夜晚...'}</span>

5. 将theme和html的属性绑定起来

只需要在设置主题色的时候将html中名为data-theme的值修改即可,例如:

js 复制代码
let theme = 'light';
export const getTheme = () => theme;
export const setTheme = (_theme) => {
    theme = _theme;
    document.documentElement.dataset.theme = _theme;
};

6. 解决刷新之后主题不保存

实现如果用户在使用过程中刷新了页面,则上述代码无法保证刷新之后恢复到刷新前的主题中去。因此,需要本地储存介入,分成两步:

    1. 在项目的入口文件中尝试读取localStorage中主题相关字段的值,并调用setTheme设置到全局变量theme中去。
    1. 每次设置完新的theme之后都将最新的值同步到localStorage中去。

一般来说,localStorage中的key会保存到src/utils/constant.js文件中:

js 复制代码
export const THEME_KEY = 'theme_mode';

然后在项目的入口文件中:

js 复制代码
import {setTheme} form 'src/utils/index.js';
import {THEME_KEY} form 'src/utils/constant.js';

try {
    const localTheme = localStorage.getItem(THEME_KEY);
    if(localTheme) setTheme(localTheme);
} catch (e) {
    console.log('init theme mode fail!');
}

总结

本文介绍了两种前端项目的主题切换策略,如果对您有所帮助,麻烦点个赞呗~

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax