持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
在2022年了,前端页面主题切换的实现方法有很多,今天我来讲一下通过css变量+setProperty来实现主题切换。具体其他的方法就不讲了,有感兴趣的可以自行了解
前言
这篇文章主要介绍怎么实现主题切换,现在市面上基本上绝大部分web和app都支持主体切换,像微信啊,ios啊 都有什么深色模式,浅色模式。更有甚者,还有定制,可以自定义颜色。
市面上常见的换肤功能主要有以下2种:
- 网站自带几套固定主题,用户只能选择有限的几个主题。
- 主题色由用户随意更改,真正做到用户的个性化定制。
今天我通过css变量来实现换肤,再换肤之前,需要先讲解一下css变量。
CSS变量
CSS变量(官方称为自定义属性)是用户定义的值,它可以在你的代码库中设置一次并多次使用。它们使管理颜色、字体、大小和动画值变得更加容易,并确保整个web应用的一致性。
举个例子,你可以将品牌颜色设置为一个CSS属性(--primarycolor: #7232FA
),并在任何使用品牌颜色的组件或样式中使用这个值(background: var(--primarycolor);
)。
除了更加简洁以及不重复的代码,CSS变量可用于构建调色板,提高响应能力,并创建动态类型系统。
var()函数
var() 函数用于插入 CSS 变量的值。
CSS 变量可以访问 DOM,这意味着您可以创建具有局部或全局范围的变量,使用 JavaScript 来修改变量,以及基于媒体查询来修改变量。
使用 CSS 变量的一种好方法涉及设计的颜色。您可以将它们放在变量中,而不必一遍又一遍地复制和粘贴相同的颜色。
var() 如何工作
首先:CSS 变量可以有全局或局部作用域。
全局变量可以在整个文档中进行访问/使用,而局部变量只能在声明它的选择器内部使用。
如需创建具有全局作用域的变量,请在 :root 选择器中声明它。 :root 选择器匹配文档的根元素。
如需创建具有局部作用域的变量,请在将要使用它的选择器中声明它。
下面的例子与上面的例子相同,但是在这里我们使用 var() 函数。
首先,我们声明两个全局变量(--blue 和 --white)。然后,我们使用 var() 函数稍后在样式表中插入变量的值:
:root {
--blue: #1e90ff;
--white: #ffffff;
}
body { background-color: var(--blue); }
h2 { border-bottom: 2px solid var(--blue); }
.container {
color: var(--blue);
background-color: var(--white);
padding: 15px;
}
button {
background-color: var(--white);
color: var(--blue);
border: 1px solid var(--blue);
padding: 5px;
}
复制代码
这样,当我们想要修改变量值,只需要修改一个地方就可以
前端换肤demo
介绍完css变量,接下来我们进入实战。先搭建一个基础的架子,有了好的架子才能实现换肤,先创建index.html文件
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./index.css">
<script src="./index.js"></script>
<link rel="stylesheet" href="../img/icon.svg">
</head>
<body>
<!-- 头部 -->
<header>
<img class="logo" src="../img/D-logo.svg" alt="">
<ul class="nav">
<li>
云居故里
</li>
<li>
柚子无敌
</li>
<li>
数据中心
</li>
</ul>
</header>
<!-- container -->
<div class="container">
<!-- 侧边栏 -->
<aside>
<ul class="sub_nav">
<li>
<img class="svg" src="../img/案例展示.svg">
我的喜欢
</li>
<li>
<img class="svg" src="../img/gongyizhanshi.svg">
我的收藏
</li>
<li>
<img class="svg" src="../img/guanzhugongzhonghao.svg">
我的查看
</li>
<li>
<img class="svg" src="../img/lunbobanner.svg">
个人中心
</li>
<li>
<img class="svg" src="../img/weiguanxinxi.svg">
福利中心
</li>
<li>
<img class="svg" src="../img/xuanfuanniu.svg">
个人设置
</li>
<li>
<img class="svg" src="../img/youhuiquan.svg">
朋友推荐
</li>
<li>
<img class="svg" src="../img/guanzhutiao.svg">
朋友圈
</li>
</ul>
</aside>
<!-- 主体 -->
<article>
<div class="card_container">
<div class="card">
<div class="header">
<span>Yyou Design</span>
<span class="more">更多</span>
</div>
<div class="body">Yyou Design是由互娱社区前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</div>
</div>
<div class="card">
<div class="header">
<span>Yyou Design</span>
<span class="more">更多</span>
</div>
<div class="body">Yyou Design是由互娱社区前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</div>
</div>
<div class="card">
<div class="header">
<span>Yyou Design</span>
<span class="more">更多</span>
</div>
<div class="body">Yyou Design是由互娱社区前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</div>
</div>
</div>
<button>+ 添加card</button>
</article>
</div>
</body>
</html>
复制代码
index.css文件
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 16px;
}
s
head, body {
width: 100vw;
height: 100vh;
overflow: hidden;
}
ul li {
list-style: none;
cursor: pointer;
}
.svg {
width: 24px;
height: 24px;
margin-right: 4px;
}
header {
display: flex;
position: relative;
align-items: center;
height: 48px;
width: 100%;
font-size: 14px;
color: #87898b;
background-color: #fff;
box-shadow: rgb(0 0 0 / 5%) 0px 4px 10px;
}
header .logo {
width: 220px;
height: 80%;
}
header .nav {
display: flex;
height: 100%;
align-items: center;
}
header .nav li {
position: relative;
padding: 6px 12px;
margin-right: 18px;
font-size: 14px;
background-color: #fff;
border-radius: 1rem;
}
header .nav li:hover {
color: #3375f1;
}
header .nav li::after {
position: absolute;
content: '';
width: 100%;
height: 2px;
bottom: 0px;
left: 0;
background-color: #3375f1;
transition: all .5s ease;
transform: scale(0);
}
header .nav li:hover::after {
transform: scale(1);
}
.container {
display: flex;
height: calc(100% - 60px);
}
.container aside {
width: 220px;
padding: 8px;
height: 100%;
background-color: #fafcff;
border-right: 1px solid #e9ebee;
}
.container aside .sub_nav li {
display: flex;
align-items: center;
width: 100%;
padding: 7px 20px;
margin-bottom: 12px;
font-size: 14px;
border-radius: 4px;
}
.sub_nav li:hover {
background-color: #ecf5fe;
}
.container article {
flex: 1;
height: 100%;
margin: 20px 20px;
}
.card_container {
display: flex;
}
article .card {
cursor: pointer;
width: 340px;
height: 200px;
font-size: 14px;
border: 1px solid #ededee;
margin-right: 40px;
border-radius: 4px;
transition: all .5s ease;
/* box-shadow: rgb(0 0 0 / 5%) 0px 4px 10px; */
}
.card .header {
color: #1d1f23;
display: flex;
font-size: 14px;
font-weight: 700;
align-items: center;
padding: 0 16px;
height: 56px;
justify-content: space-between;
border-bottom: 1px solid #ededee;
}
.card .header .more {
font-weight: 400;
color: #3375f1;
}
.card .body {
padding: 10px 16px;
font-size: 14px;
color: #87898b;
}
article .card:hover {
box-shadow: rgb(0 0 0 / 5%) 0px 4px 10px;
}
button {
cursor: pointer;
width: 96px;
height: 32px;
border: 0px;
margin-top: 20px;
border-radius: 4px;
background-color: #3375f1;
font-size: 14px;
color: #fff;
}
复制代码
写好html和css后,页面大概长这样子
基本页面搭建完后,我们要实现换肤,首先得有个button,就添加card这个按钮旁边吧
<button>+ 添加card</button>
<button>切换简约风格</button>
<button>切换暗黑风格</button>
<button>切换炫彩风格</button>
复制代码
按钮有了,接下来我们得把css里需要动态变化的量提取出来,换成var()
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- <link rel="stylesheet" href="./index.css"> -->
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 16px;
}
:root {
--theme_btn: #3375f1;
--theme_shadow: rgb(0 0 0 / 5%) 0px 4px 10px;
--theme_size_color: #87898b;
--theme_card_bgc: #fff;
--theme_aside_bgc: #fafcff;
--theme_article_bgc: #fff;
--theme_size: #000;
}
head,
body {
width: 100vw;
height: 100vh;
overflow: hidden;
}
ul li {
list-style: none;
cursor: pointer;
}
.svg {
width: 24px;
height: 24px;
margin-right: 4px;
}
header {
display: flex;
position: relative;
align-items: center;
height: 48px;
width: 100%;
font-size: 14px;
color: var(--theme_size_color);
background-color: var(--theme_card_bgc);
box-shadow: var(--theme_shadow);
}
header .logo {
width: 220px;
height: 80%;
}
header .nav {
display: flex;
height: 100%;
align-items: center;
}
header .nav li {
position: relative;
padding: 6px 12px;
margin-right: 18px;
font-size: 14px;
background-color: #fff;
border-radius: 1rem;
}
header .nav li:hover {
color: var(--theme_btn);
}
header .nav li::after {
position: absolute;
content: '';
width: 100%;
height: 2px;
bottom: 0px;
left: 0;
background-color: var(--theme_btn);
transition: all .5s ease;
transform: scale(0);
}
header .nav li:hover::after {
transform: scale(1);
}
.container {
display: flex;
height: calc(100% - 48px);
}
.container aside {
width: 220px;
padding: 8px;
height: 100%;
color: var(--theme_size);
background-color: var(--theme_aside_bgc);
border-right: 1px solid #e9ebee;
}
.container aside .sub_nav li {
display: flex;
align-items: center;
width: 100%;
padding: 7px 20px;
margin-bottom: 12px;
font-size: 14px;
border-radius: 4px;
}
.sub_nav li:hover {
background-color: #ecf5fe;
}
.container article {
flex: 1;
height: 100%;
padding: 20px 20px;
background-color: var(--theme_article_bgc);
}
.card_container {
display: flex;
}
article .card {
cursor: pointer;
width: 340px;
height: 200px;
font-size: 14px;
border: 1px solid #ededee;
margin-right: 40px;
border-radius: 4px;
transition: all .5s ease;
background-color: var(--theme_card_bgc);
/* box-shadow: rgb(0 0 0 / 5%) 0px 4px 10px; */
}
.card .header {
color: var(--theme_size);
display: flex;
font-size: 14px;
font-weight: 700;
align-items: center;
padding: 0 16px;
height: 56px;
justify-content: space-between;
border-bottom: 1px solid #ededee;
}
.card .header .more {
font-weight: 400;
color: var(--theme_btn);
}
.card .body {
padding: 10px 16px;
font-size: 14px;
color: var(--theme_size_color);
}
article .card:hover {
box-shadow: var(--theme_shadow);
}
button {
cursor: pointer;
width: 96px;
height: 32px;
border: 0px;
margin-top: 20px;
border-radius: 4px;
background-color: var(--theme_btn);
font-size: 14px;
color: #fff;
}
</style>
<script src="./index.js"></script>
</head>
<body>
<!-- 头部 -->
<header>
<img class="logo" src="../img/D-logo.svg" alt="">
<ul class="nav">
<li>
云居故里
</li>
<li>
柚子无敌
</li>
<li>
数据中心
</li>
</ul>
</header>
<!-- container -->
<div class="container">
<!-- 侧边栏 -->
<aside>
<ul class="sub_nav">
<li>
<img class="svg" src="../img/案例展示.svg">
我的喜欢
</li>
<li>
<img class="svg" src="../img/gongyizhanshi.svg">
我的收藏
</li>
<li>
<img class="svg" src="../img/guanzhugongzhonghao.svg">
我的查看
</li>
<li>
<img class="svg" src="../img/lunbobanner.svg">
个人中心
</li>
<li>
<img class="svg" src="../img/weiguanxinxi.svg">
福利中心
</li>
<li>
<img class="svg" src="../img/xuanfuanniu.svg">
个人设置
</li>
<li>
<img class="svg" src="../img/youhuiquan.svg">
朋友推荐
</li>
<li>
<img class="svg" src="../img/guanzhutiao.svg">
朋友圈
</li>
</ul>
</aside>
<!-- 主体 -->
<article>
<div class="card_container">
<div class="card">
<div class="header">
<span>Yyou Design</span>
<span class="more">更多</span>
</div>
<div class="body">Yyou Design是由互娱社区前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</div>
</div>
<div class="card">
<div class="header">
<span>Yyou Design</span>
<span class="more">更多</span>
</div>
<div class="body">Yyou Design是由互娱社区前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</div>
</div>
<div class="card">
<div class="header">
<span>Yyou Design</span>
<span class="more">更多</span>
</div>
<div class="body">Yyou Design是由互娱社区前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</div>
</div>
</div>
<button>+ 添加card</button>
<button id="common">切换简约风格</button>
<button id="block">切换暗黑风格</button>
<button id="colorful">切换炫彩风格</button>
</article>
</div>
</body>
</html>
复制代码
注意,这里我们把index.css的代码,全部通过内嵌放到了index.html中,这是因为后面如果用js修改变量的话,如果是link引入的样式,受游览器同源影响,是无法修改的,会导致报错。所以我们把css放到了html中
有了css变量,最后我们只需要写js代码,实现动态切换就可以了
// index.js
window.onload = function () {
const commonBtn = document.getElementById('common');
const blockBtn = document.getElementById('block');
const colorfulBtn = document.getElementById('colorful');
const ThemeSwitch = {
common: {
'--theme_btn': '#3375f1',
'--theme_shadow': 'rgb(0 0 0 / 5 %) 0px 4px 10px',
'--theme_size_color': '#87898b',
'--theme_card_bgc': '#fff',
'--theme_aside_bgc': '#fafcff',
'--theme_article_bgc': '#fff',
'--theme_size': '#000',
},
block: {
'--theme_btn': 'purple',
'--theme_shadow': 'rgb(255 255 255 / 20 %) 0px 4px 10px',
'--theme_size_color': 'pink',
'--theme_card_bgc': 'block',
'--theme_aside_bgc': '#000',
'--theme_article_bgc': '#000',
'--theme_size': '#fff',
},
colorful: {
'--theme_btn': 'skyblue',
'--theme_shadow': 'rgb(0 0 0 / 5 %) 0px 4px 10px',
'--theme_size_color': 'orange',
'--theme_card_bgc': 'skyblue',
'--theme_aside_bgc': 'orange',
'--theme_article_bgc': 'pink',
'--theme_size': '#000',
},
}
console.log(document.body.style)
commonBtn.addEventListener('click', (e) => {
Object.keys(ThemeSwitch.common).reduce((acc, item) => {
document.styleSheets[0].cssRules[0].style.setProperty(item, ThemeSwitch.common[item])
}, [])
})
console.log(1)
blockBtn.addEventListener('click', (e) => {
Object.keys(ThemeSwitch.block).reduce((acc, item) => {
document.styleSheets[0].cssRules[0].style.setProperty(item, ThemeSwitch.block[item])
}, [])
})
colorfulBtn.addEventListener('click', () => {
Object.keys(ThemeSwitch.colorful).reduce((acc, item) => {
document.styleSheets[0].cssRules[0].style.setProperty(item, ThemeSwitch.colorful[item])
}, [])
})
}
复制代码
最后,让我们来看一下效果图
大功告成,最后代码放码上掘金,一起来玩玩吧