前端实现主题(深色模式)切换的几种方案
方案一:link 动态引入
通过改变link 标签的 href 属性实现动态修改样式(暂不推荐这种方案)
优点:实现了按需加载,提高了性能;
缺点:动态加载样式文件,可能会因为网络问题导致样式加载过慢;
? ? ? ? ? ?可维护性较差,后续新增或修改主题较为麻烦。
方案二:提前引入样式,类名切换
在这个方案中,我们只有一个css文件,然后通过js来改变他的类名(也暂不推荐这种方案)
优点:相比方案一,不会因为网络问题导致样式切换延迟;
缺点:样式文件过大时可能会出现首屏加载过慢问题;
? ? ? ? ? ?可维护性依旧较差,后续新增或修改主题较为麻烦;
方案三:CSS 滤镜
利用CSS3新增的filter属性(需求简单可以使用)
优点:一行代码实现黑色主题功能,简单易于维护;
缺点:不能满足需求的要求,不能实现对区域的主题颜色自定义;
方案四:CSS变量+类名切换(目前的主流方案)
VUE3官方文档使用的解决方案(比较推荐),这一个方案也是我目前使用的方案
实现思路:首先定义几个我们需要的全局样式变量,之后定义几个集合属性<html lang="en" data-theme="dark">(不同的主题样式),然后将其放在html根元素标签里,再动过js动态的切换这个集合属性就可以实现主题的切换,具体看以下代码;
优点:不会因为网络问题导致样式切换延迟;
? ? ? ? ? ?在需要切换主题的地方利用 var0绑定变量即可,不存在优先级问题;
? ? ? ? ? ?新增或修改主题方便灵活,仅需新增或修改 CSS 变量即可,在 var()绑定样式变量的地? ? ? ? ? ? ?方就会自动更换;
缺点:首屏加载时会牺牲一些时间加载样式资源;
预览效果
具体实现
<!DOCTYPE html>
<!-- <html lang="en" data-theme="light"> -->
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>王国梁</title>
<link rel="shortcut icon" href="./img/w.png" type="image/x-icon">
<!-- 引入谷歌字体 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Dhurjati&family=Noto+Sans+SC:wght@400;500;600;700;800;900&display=swap"
rel="stylesheet">
<!-- 自定义样式 -->
<link rel="stylesheet" href="./index.css">
<style>
.container {}
</style>
</head>
<body>
<!-- 标题部分 -->
<header>
<a href="#" class="logo"><span>W</span>GL</a>
<ul class="nav-bar">
<li><a href="#">首页</a></li>
<li><a href="#">教育背景</a></li>
<li><a href="#">技术栈</a></li>
<li><a href="#">经历</a></li>
<li><a href="#">博客</a></li>
<li><a href="#">联系我</a></li>
</ul>
<div>
<span>更多</span>
<div></div>
</div>
<button onclick="toggle()" class="toggle">切换主题</button>
<!-- <theme-button value="dark" id="btn" size="3"></theme-button> -->
</header>
<!-- 自定义js文件链接 -->
<script src="./index.js"></script>
</body>
</html>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "rubik",sans-serif;
list-style: none;
text-decoration: none;
}
@media screen and (max-width: 768px) {
}
/* 全局样式变量 */
:root{
/* 背景色/边框颜色/主色/辅色/其他色 */
--color-border:#deddee;
--color-main:#ffae00;
--color-auxiliary:#00ff11;
--color-other:#00ffdd;
--color-bg:#1f1f21;
--font-color-main:#ffffff;
--font-color-secondary:#ffffffb3;
--font-color-auxiliary:#ffffff3b;
/* 字号和字体颜色 */
--font-root:1rem;
--font-32px:2rem;
--font-20px:1.25rem;
--font-18px:1.125rem;
--font-16px:1rem;
--font-14px:.875rem;
--font-12px:.75rem;
--font-10px:.625rem;
/* 层级 */
--z-index10:10;
--z-index100:100;
--z-index1000:1000;
/* 间距 */
--spacing-2:.125rem;
--spacing-4:.25rem;
--spacing-6:.375rem;
--spacing-8:.5rem;
--spacing-10:.625rem;
--spacing-12:.75rem;
--spacing-14:.875rem;
--spacing-16:1rem;
--spacing-20:1.25rem;
--spacing-24:1.5rem;
--spacing-30:1.875rem;
--spacing-40:2.5rem;
--spacing-50:3.125rem;
--spacing-60:3.75rem;
}
/* 集合属性(主题样式) */
[data-theme="dark"] {
--color-bg:#1f1f21;
--color-btn:#ffffff;
--color-btn-font:#333333;
--color-border:#deddee;
--color-main:#ffae00;
--color-auxiliary:#00ff11;
--color-other:#00ffdd;
--font-color-main:#ffffff;
--font-color-secondary:#ffffffb3;
--font-color-auxiliary:#ffffff3b;
}
[data-theme="light"] {
--color-bg:#ffffff;
--color-btn:#000000;
--color-btn-font:#ffffff;
--color-border:#deddee;
--color-main:#ffae00;
--color-auxiliary:#00ff11;
--color-other:#00ffdd;
--font-color-main:#333333;
--font-color-secondary:#777777;
--font-color-auxiliary:#aaaaaa;
}
/* 切换按钮 */
.toggle{
border: none;
padding: var(--spacing-6);
font-size: var(--font-14px);
background-color: var(--color-btn);
color: var(--color-btn-font);
border-radius: .25rem;
transition: all ease .45s;
}
body{
background: var(--color-bg);
color: var(--font-color-main);
overflow-x: hidden;
transition: all 0.5s ease-in-out;
}
/* 标题部分 */
header{
position: fixed;
top: 0;
right: 0;
width: 100%;
background: transparent;
z-index: var(--z-index10);
font-size: var(--font-14px);
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--spacing-30) 15%;
transition: all ease .45s;
}
.logo{
color: var(--font-color-main);
font-weight: 600;
font-size: var(--font-32px);
}
.logo span{
color: var(--color-main);
}
.nav-bar{
display: flex;
}
.nav-bar a{
font-size: var(--font-14px);
color: var(--font-color-secondary);
margin:0 var(--spacing-24);
transition: all ease.5s;
}
.nav-bar a:hover{
color: var(--color-main);
font-weight: 600;
}
// 切换主题
function toggle() {
let html = document.querySelector('html')
let currentTheme = html.getAttribute('data-theme');
if (currentTheme === "light") {
html.setAttribute('data-theme', 'dark');
} else {
html.setAttribute('data-theme', 'light');
}
}
方案五:v-bind (Vue3)
在vue3中基于响应式对css变量进行动态改变
优点:不用考虑网络问题;
? ? ? ? ? ?在需要切换主题的地方利用 v-bind 绑定变量即可,不存在优先级问题;
? ? ? ? ? ?新增或修改主题方便灵活,仅需新增或修改JS 变量即可,在v-bind0绑定样式变量的地方就? ???????????会自动更换;
缺点:也是首屏加载时会牺牲一些时间加载样式资源;
? ? ? ? ? ?这种方式只要是在组件上绑定了动态样式的地方都会有对应的编译成哈希化的 CSS 变量,? ? ? ? ? ? ?而不像 CSS变量一样统一地在:root 上设置;
还有剩下的一些方案就不一一介绍了,感觉有用就点个赞再走吧
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!