前言
在项目开发中,一般情况下,我们都不希望我们的站点是一成不变的,经常会有多主题的需求,如常见的浅色和深色主题
现在,较新版本的操作系统基本都可以支持深色模式了,很多应用、网页为了提高用户体验,也会有适配系统主题的浅色深色主题,当系统处于深色模式,打开应用、网页,显示的也为对应的深色模式主题,而不是说依旧为浅色主题,会给用户一种很亮的感觉,刺激用户感官
具体实现
根据不同的需求,我们可以实现多套主题,以下仅从浅色和深色主题举例介绍
原理分析
主题,即UI风格,如背景色、文字颜色、文字大小等
在前端中,每一套主题其实就是对应着一套CSS样式表,多主题的切换,其实就是样式表的切换
主题实现
实现多主题的方式有很多种,常见的就是通过变量,不同主题对应一套不同的变量值表(变量名一致),在编写CSS时,我们不使用具体的值,而是使用变量,在切换主题时,就是切换不同变量值表,对应的CSS样式就会对应呈现出来,能够较好地实现多主题,也不需要多复杂的操作
主题切换
主题切换的方式可以有很多种
如果是有多个主题,由用户选择控制主题变化,可以用JS配合CSS类或元素自定义属性实现
- 当用户选择切换主题时,比如切换到dark主题,那么就给html或body添加一个名为dark的类;或者添加一个自定义属性(如:data-theme),设置其值为dark,然后在CSS内可针对这些约定好的特性设置对应的样式、变量值等
如果只有浅色和深色主题,并且希望根据用户系统主题进行自动切换,可以使用@media的一个特性prefers-color-scheme,其可以检测用户系统当前的主题色
- prefers-color-scheme,其可以检测用户系统当前的主题色,其有三个值
- no-preference — 表示获取不到,可能用户浏览器不支持该属性或功能被禁止
- light — 表示系统当前为浅色主题
- dark — 表示系统当前为深色主题
- 其大致使用方法如下:
- 以上示例中,当系统主题为深色时,body背景色呈现为#000,反之则呈现为#fff
举个栗子
以下均从浅色和深色两个主题进行讲解,更多主题可自行扩展
CSS实现方式
首先,我们定义套变量表
- 第一种采用自定义属性进行区分,切换主题时,只需将html元素的data-theme值改为对应主题值即可
- 第二种采用@media进行媒体查询判断,当系统为浅色主题,则会自动渲染相应主题(无效可能为浏览器问题,可查看浏览器主题是否设置跟随系统)
当然主题不一定只是变量的变化,也可以是不同样式、布局等,同样的只需用类似上面变量定义的方法,用对应的方法进行约束,如下:
如上,简单展示了不同主题,不同布局的情况,用相同的类达到目的
- 用自定义属性的方式,那么选择器均需通过html[data-theme="value"]进行约束
- 用@media的方式,则需将选择器样式写于@media范围内
SCSS实现方式
实现纯CSS的方式可以达到想要效果,但过程会稍显繁复,且大量使用CSS变量可能有一定的性能问题(虽然理论上并不会有明显问题)
我们可以用SCSS的能力简化我们的主题样式编写,同时通过SCSS变量最终编译出的CSS使用的是固定静态值
首先,为了结构比较清晰,可以把主题变量单纯定义在一个文件内,方便扩展,如下:
接着,定义一些mixin和function,用于方便主题开发,如下
使用如下,只需在需编写主题样式的样式表内引入该文件使用即可
生成CSS如下:
使用这种方式,在项目的任何位置,如果需要编写主题相关样式,只需引入上侧index.scss文件即可,参考上侧app.scss使用即可
如果你是用框架开发,如Vue,可以进行一些配置,使其注入到全局,这样就不用使用时都要引入index.scss,如下
在配置文件vite.config.ts内配置
通过这种配置,在项目中编写主题样式时,直接使用useTheme这些方法即可
通过SCSS可以大大地节省我们编写复杂样式的时间,还可以进行一些复杂运算,如根据主题色计算出其它搭配色等操作,有兴趣的可自行深入