css主题切换

9 阅读2分钟

主流方案分为 2 种,1、css变量;2、如果考虑兼容性,则写2套class

借助css变量实现

原生css变量

在html标签上使用自定义属性进行标识

/* 暗色主题 */
html[data-theme='dark']{
    --bg-color: #000;
}

/* 默认主题/浅色主题 */
:root{
    --bg-color: #fff;
}

css选择器特定性(其实是浏览器计算样式权重的一种方式)

选择器的特殊性由选择器本身的组件确定。特殊性值表述为 4 个部分,如:0, 0, 0, 0。一个选择器的具体特殊性如下确定:

  • 对于选择器中给定的各个 ID 属性值,加 0, 1, 0, 0。
  • 对于选择器中给定的各个类属性值、属性选择或伪类,加 0, 0, 1, 0。
  • 对于选择器中给定的各个元素和伪元素,加 0, 0, 0, 1。伪元素是否有特殊性?在这方面 CSS2 有些自相矛盾,不过 CSS2.1很清楚地指出,伪元素有特殊性,百且特殊性为 0, 0, 0, 1。
  • 结合符和通配符选择器对特殊性没有任何贡献(后面还会更多地介绍这些值)。

例如,以下规则中选择器的特殊性见注释:

h1 { color: red; } /* specificity = 0, 0, 0, 1 */
p em { color: purple; } /* specificity = 0, 0, 0, 2 */
.grape ( color: purple } /* specificity = 0, 0, 1, 0     */
*.bright { color: yellow } /* specificity = 0, 0, 1, 0     */
p.bright em.dark { color: maroon} /* specificity = 0, 0, 2, 2 */
#id216 { color: blue; } /* specifity = 0, 1, 0, 0 */
div#sidebar *[href] { color: silver } /* 0, 1, 1, 1 */

所以上述主题间切换时,如果不想过分关注书写顺序,则需要注意css选择器特定性的计算,如添加html标签选择器,增加特殊性

用户点击切换主题时,通过js动态更改html标签上的data-theme的值

function toggle(theme)
    document.documentElement.setAttribute('data-theme', theme);
}

此外可借助localStorage实现持久化。 定义一个变量key,每次主题变化时,进行存储,每次进入页面时从localStorage中取值。

less等预编译器

具体步骤如下:

  1. 使⽤ Less 预编译器来编译 Less ⽂件为 CSS ⽂件。
  2. 在 HTML ⽂件中引⼊编译后的 CSS ⽂件。
  3. 在 JavaScript 中动态修改 Less 变量的值。
  4. 使⽤ JavaScript 将新的 Less 变量值注⼊到编译后的 CSS ⽂件中。
  5. 将注⼊后的 CSS 样式应⽤到⻚⾯上。
// base.less ⽂件
@primary-color: #007bff; .btn {background-color: @primary-color; }
// dark.less ⽂件
@primary-color: #343a40;
function changeSkin() {
    // 修改 Less 变量的值
    less.modifyVars({'@primary-color': '#28a745' }).then(() => {
        console.log('换肤成功');
    }).catch(() => {console.error('换肤失败'); });
}

2种样式表,用户切换后,更换引入路径

function setTheme(theme = 'ligth') {
    let link = document.querySelector('#theme-link');
    let href = "/theme/" + theme + ".css";
    if (!link) {
        let head = document.querySelector('head');
        link = document.createElement('link');
        link.id = '#theme-link';
        link.rel = "stylesheet";
        link.href = href;
        head.appendChild(link);
    } else {
        link.href = href;
    }
}