css
/* 全局需要根据lang动态修改的样式 */
:root {
--font-size: 16px;
--font-family: Arial, sans-serif;
}
/* 默认dark主题 */
:root[theme='red'] {
--text-color: #f0f6fc;
--themeColor: #fd2d60;
}
/* light主题 */
:root[theme='blue'] {
--text-color: #f0f6fc;
--themeColor: #50a5de;
}
在开发web端系统的时候,经常需要配置不同的主题来实现不同的样式切换,比如白天和黑夜模式,编辑器的不同颜色主题等,这些的底层原理是什么?
主要就是:
css
:root[theme='red']
这行代码的含义,可以分解为:
-
:root:伪类选择器,匹配文档的根元素(HTML文档中是<html>标签) -
[theme='red']:属性选择器,匹配具有theme属性且值为"red"的元素 -
组合起来 :选择
<html theme="red">这个元素
作用:创建条件样式规则
相当于说:
"当html元素的theme属性等于'red'时,应用这些CSS变量值"
css
<!-- 当HTML元素是这样时 -->
<html theme="red">
<!-- 应用red主题的CSS变量 -->
</html>
<!-- 当HTML元素是这样时 -->
<html theme="blue">
<!-- 应用blue主题的CSS变量 -->
</html>
JavaScript切换主题:
css
// 切换到红色主题
document.documentElement.setAttribute('theme', 'red');
// 切换到蓝色主题
document.documentElement.setAttribute('theme', 'blue');
CSS工作原理:
css
/* 当theme="red"时应用这些变量 */
:root[theme='red'] {
--themeColor: #fd2d60; /* 红色主题主色 */
--mainBgImg: url('@/assets/images/redMainBg.png');
}
/* 当theme="blue"时应用这些变量 */
:root[theme='blue'] {
--themeColor: #50a5de; /* 蓝色主题主色 */
--mainBgImg: url('@/assets/images/blueMainBg.png');
}
写法1:属性选择器(你的写法)
css
:root[theme='red'] {
--themeColor: #fd2d60;
}
写法2:类名选择器
css
.theme-red {
--themeColor: #fd2d60;
}
/* 使用时 */
document.documentElement.className = 'theme-red';
写法3:data属性选择器
css
:root[data-theme='red'] {
--themeColor: #fd2d60;
}
/* 使用时 */
document.documentElement.setAttribute('data-theme', 'red');
CSS优先级示例
css
/* 默认值 */
:root {
--themeColor: #ccc; /* 默认灰色 */
}
/* 当有theme属性时覆盖 */
:root[theme] {
--themeColor: #000; /* 任何theme属性时变成黑色 */
}
/* 具体theme值时再次覆盖 */
:root[theme='red'] {
--themeColor: #f00; /* theme="red"时红色,优先级最高 */
}
/* 优先级顺序:
:root[theme='red'] > :root[theme] > :root
*/
与普通选择器的区别
css
/* 普通CSS(一直生效) */
.red-theme {
color: red;
}
/* 属性选择器(有条件生效) */
[theme='red'] {
color: red;
}
/* 组合选择器(更精确) */
html[theme='red'] {
color: red;
}
/* :root选择器(目标根元素) */
:root[theme='red'] {
color: red;
}
主题切换的完整示例
css
// 主题切换函数
function switchTheme(themeName) {
// 1. 修改html元素的theme属性
document.documentElement.setAttribute('theme', themeName);
// 2. 保存用户偏好
localStorage.setItem('app-theme', themeName);
// 3. 触发事件通知
window.dispatchEvent(new CustomEvent('themechange', {
detail: { theme: themeName }
}));
}
// 初始化主题
const savedTheme = localStorage.getItem('app-theme') || 'red';
switchTheme(savedTheme);
优点和注意事项
优点:
-
语义清晰:直接表示"主题",易于理解
-
无需额外类名:避免与现有类名冲突
-
优先级明确:可以与其他选择器组合使用
注意事项:
-
属性值区分大小写 :
theme='Red'和theme='red'是不同的 -
没有theme属性时的回退:建议添加默认值
-
验证属性值:JavaScript中可能需要验证theme值是否有效
建议的改进写法:
css
/* 默认主题(回退) */
:root {
--themeColor: #fd2d60; /* 默认红色主题 */
--mainBgImg: url('@/assets/images/redMainBg.png');
}
/* 显式指定主题 */
:root[theme='red'] {
/* 可以省略,使用默认值 */
}
:root[theme='blue'] {
--themeColor: #50a5de;
--mainBgImg: url('@/assets/images/blueMainBg.png');
}
/* 无效主题时的回退 */
:root[theme]:not([theme='red']):not([theme='blue']) {
--themeColor: #fd2d60; /* 回退到红色 */
}
实际应用案例:
