前端实现主题(深色模式)切换的几种方案
后台-插件-广告管理-内容页头部广告(手机) |
方案一:link 动态引入
通过改变link 标签的 href 属性实现动态修改样式(暂不推荐这种方案)
优点:实现了按需加载,提高了性能;
缺点:动态加载样式文件,可能会因为网络问题导致样式加载过慢;
可维护性较差,后续新增或修改主题较为麻烦。
方案二:提前引入样式,类名切换
在这个方案中,我们只有一个css文件,然后通过js来改变他的类名(也暂不推荐这种方案)
优点:相比方案一,不会因为网络问题导致样式切换延迟;
缺点:样式文件过大时可能会出现首屏加载过慢问题;
可维护性依旧较差,后续新增或修改主题较为麻烦;
方案三:CSS 滤镜
利用CSS3新增的filter属性(需求简单可以使用)
优点:一行代码实现黑色主题功能,简单易于维护;
缺点:不能满足需求的要求,不能实现对区域的主题颜色自定义;
方案四:CSS变量+类名切换(目前的主流方案)
VUE3官方文档使用的解决方案(比较推荐),这一个方案也是我目前使用的方案
实现思路:首先定义几个我们需要的全局样式变量,之后定义几个集合属性(不同的主题样式),然后将其放在html根元素标签里,再动过js动态的切换这个集合属性就可以实现主题的切换,具体看以下代码;
优点:不会因为网络问题导致样式切换延迟;
在需要切换主题的地方利用 var0绑定变量即可,不存在优先级问题;
新增或修改主题方便灵活,仅需新增或修改 CSS 变量即可,在 var()绑定样式变量的地 方就会自动更换;
缺点:首屏加载时会牺牲一些时间加载样式资源;
预览效果
具体实现
- html>
- <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>Wspan>GLa>
- <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>
- header>
- <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 上设置;
还有剩下的一些方案就不一一介绍了,感觉有用就点个赞再走吧
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |