haizhilingyu 的个人知识记录

Open Source, Open Mind,
Open Sight, Open Future!

利用css变量实现切换主题的几种方式

{% series %}

利用[[../../C4-归档资料/4.1学习类/收藏网址]]变量实现切换主题的几种方式

这么久就写了一篇文章,今天休假,趁着两个儿子睡着啦来讲讲怎样利用css实现主题的切换。
css变量语法如下,更多css用法参考mdn的 Using_CSS_custom_properties:

/* 定义方式1 */
:root{
  --body: rgba(0,0,0,0.88);
}

/* 定义方式2 */
[data-theme="light"]{
  --body: rgba(0,0,0,0.88);
}

实现方式1

另一种就是不考虑提供自定义主题,我们设置固定的几套由UI精心设计的主题,相对的css代码会多一些,用户不需要考虑那么多,直接简单切换喜欢的主题。

下面是代码示例:

<!DOCTYPE html>
<!-- 默认主题是在这里设置data-theme属性 -->
<html lang="zh" data-theme="dark">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>样式设置</title>
    <style>

        /* 定义深色主题 */
        [data-theme="dark"] {
            --body: rgba(0, 0, 0, 0.88);
            --color: rgba(255, 255, 255, 0.88);
        }

        /* 定义亮色主题 */
        [data-theme="light"] {
            --body: rgba(255, 255, 255, 0.88);
            --color: rgba(0, 0, 0, 0.88);
        }  

        body {
            /* 用变量设置界面背景颜色 */
            background-color: var(--body);
            /* 用变量设置文字颜色 */
            color: var(--color);
            margin: 0;
            height: 100vh;
            display: grid;
            align-content: center;
            justify-items: center;
        }

        #theme-toggle{
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div>
        <div>
            <!-- 主题切换 -->
            <div id="theme-toggle">
                <!-- 太阳图标 -->
                <svg id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sun"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22" ></line></svg>
                <!-- 月亮 -->
                <svg id="moon" style="display: none;" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-moon"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
            </div>
        </div>
    </div>
    <script>
        const themeToggle = document.getElementById("theme-toggle");
        const moonPath = document.getElementById("moon");
        const sunPath = document.getElementById("sun");

        // 为主题切换div添加点击事件
        themeToggle.addEventListener("click", () => {
            if (!isDark()) {
                // 隐藏月亮图标
                moonPath.style.display = "none";
                // 显示太阳图标
                sunPath.style.display = "block";
                // 设置主题为暗色
                document.documentElement.setAttribute("data-theme", "dark");
            } else {
                // 显示月亮图标
                moonPath.style.display = "block";
                // 隐藏太阳图标
                sunPath.style.display = "none";
                // 设置主题为亮色
                document.documentElement.setAttribute("data-theme", "light");
            }
        });

        // 判断是否为暗色主题
        function isDark() {
            return "dark"==document.documentElement.getAttribute("data-theme")
        }
    </script>
</body>
</html>


实现方式2

这个思路是html中只定义一套默认变量,然后界面提供主题选择利用javascript进行变量的替换,将替换后的变量标识记录到浏览器的localStorage中,重新进入页面时读取localStorage进行默认切换,后续如有自定义主题的需求也方便扩展,可以利用后端存储主题变量,加载页面时读取列表供用户进行切换及自定义主题。

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>样式设置</title>
    <style>

        /* 定义默认变量 */
        :root {
            --body: rgba(0, 0, 0, 0.88);
            --color: rgba(255, 255, 255, 0.88);
        }

        body {
            /* 用变量设置界面背景颜色 */
            background-color: var(--body);
            /* 用变量设置文字颜色 */
            color: var(--color);
            margin: 0;
            height: 100vh;
            display: grid;
            align-content: center;
            justify-items: center;
        }

        .click{
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div>
        <div>
                <!-- 太阳图标 -->
                <svg class="click" id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sun"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22" ></line></svg>
                <!-- 月亮 -->
                <svg class="click" id="moon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-moon"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
            
        </div>
    </div>
    <script>
        const moonPath = document.getElementById("moon");
        const sunPath = document.getElementById("sun");

        // 为月亮图标添加点击事件,切换到暗色
        moonPath.addEventListener("click", () => {
            switchTheme("dark")
        });

        // 为太阳图标添加点击事件,切换到亮色
        sunPath.addEventListener("click", () => {
            switchTheme("light")
        });


        // 支持切换的样式缓存map
        const themeMap ={
            dark: {
                '--body':'rgba(0, 0, 0, 0.88)',
                '--color':'rgba(255, 255, 255, 0.88)',
            },
            light: {
                '--body':'rgba(255, 255, 255, 0.88)',
                '--color':'rgba(0,0,0, 0.88)',
            }
        }

        //  执行切换样式的函数
        function switchTheme(theme) {
            const root = document.querySelector(':root');
            // 获取需要切换的样式对象
            const themePropertys = themeMap[theme];
            // 获取所用对象key
            const keys = Object.keys(themePropertys);
            if(keys.length>0){
                // 循环变更变量属性值
                for (let index = 0; index < keys.length; index++) {
                    const propertyKey = keys[index];
                    root.style.setProperty(propertyKey, themePropertys[propertyKey]);
                }
            }
        }
    </script>
</body>
</html>

好了,娃儿在哭了,我要去带娃,你们去试试吧


标题:利用css变量实现切换主题的几种方式
作者:haizhilingyu
地址:https://xiweihai.site/articles/2024/03/17/1710605207155.html