一直想着给 babyblue 添加黑夜模式,终于拖延到今天动手,在未开始之前总觉得修改东西会很麻烦,真正做起来倒觉得事情都很简单,还学到了新东西,趁此总结一下。
CSS 一键反转
1 2 3
| html{ filter: invert(1) hue-rotate(180deg); }
|
- filter
CSS 属性 filter 将模糊或颜色偏移等图形效果应用于元素。滤镜通常用于调整图像、背景和边框的渲染。
blur(1px) 函数用于模糊图像;brightness(0.5)函数 用于调整图像的亮度;contrast(2) 函数用于调整图像的对比度;grayscale(1) 函数用于调整图像的灰度;hue-rotate() 函数用于旋转图像的色相;invert(1) 函数用于反转图像的颜色;opacity(0.5) 函数用于调整图像的不透明度;saturate(100) 函数用于调整图像的饱和度;sepia(0.5) 函数用于调整图像的褐色;drop-shadow(x 偏移, y 偏移, 模糊大小, 色值) 函数用于为图像添加阴影。
prefers-color-scheme CSS 媒体特性用于检测用户是否有将系统的主题色设置为亮色或者暗色。
- no-preference 表示系统未得知用户在这方面的选项。在布尔值上下文中,其执行结果为 false。
- light 表示用户已告知系统他们选择使用浅色主题的界面。
- dark 表示用户已告知系统他们选择使用暗色主题的界面。
1 2 3 4 5 6 7 8 9
| @media (prefers-color-scheme: dark){ .theme-icon background-image: url('/images/dark.png') } @media (prefers-color-scheme: light) { .theme-icon background-image: url('/images/light.png') }
|
如上,可以将媒体查询放在一个 CSS 样式文件里。
为了更好的修改和维护,也可以分别设置 dark.css、light.css 文件,style.css 存放为其他通用的样式,使用 CSS 变量定义不同的主题颜色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| :root { --background-color:#1f1f1f; --text-color: #ccc; --link-color: #ececec; }
:root { --background-color: #fff; --text-color: #404040; --link-color:#2196f3; }
body { background-color: var(--background-color); color:var(--text-color); } a { color: var(--link-color); }
|
1 2 3 4
| <link rel="stylesheet" href="/style.css"> <link rel="stylesheet" href="/dark.css" media="(prefers-color-scheme: dark)"> <link rel="stylesheet" href="/light.css" media="(prefers-color-scheme: no-preference),(prefers-color-scheme: light)"
|
:root 这个 CSS 伪类匹配文档树的根元素。对于 HTML 来说,:root 表示 <html> 元素,除了优先级更高之外,与 html 选择器相同,通常用来声明全局 CSS 变量。
通过 JS 控制主题
通过媒体查询系统的主题色决定网页的主题很方便,但是想要用户能够主动交互切换主题时,媒体查询就无能为力了,这个时候就要靠 JS 操作。
前面分别为 light/dark 模式设置了不同颜色的变量,为了控制在不同模式下响应的变量,可以通过属性选择器控制根节点 CSS 变量。
1 2 3 4 5 6 7 8 9 10 11 12
| html[data-theme="dark"]:root { --progress-color:linear-gradient(to right, #c2e59c, #64b3f4) --background-color:#1f1f1f --text-color: #ccc; }
html[data-theme="light"]:root{ --progress-color:linear-gradient(to right, #c2e59c, #64b3f4) --background-color: #fff; --text-color: #404040; }
|
在页面初始化时通过 JS 获取系统的主题方案以修改 data-theme 的值,同时也可以响应用户的点击切换 light/dark 模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <script> const toggleTheme = (isDarkMode) => { document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light'); }; const theme = localStorage.getItem('theme'); const themeMedia = window.matchMedia('(prefers-color-scheme: dark)'); if (theme) { toggleTheme(theme === 'dark'); } else { toggleTheme(themeMedia.matches); } themeMedia.addEventListener('change', (e) => { toggleTheme(e.matches); }); </script>
|
现在可以通过监听用户点击事件交互切换 dark/light 模式。
1 2 3 4 5 6 7 8
| const htmlEl = document.documentElement; const buttonEl = document.getElementById("btn"); buttonEl.addEventListener("click", () => { const currentTheme = htmlEl.getAttribute("data-theme"); const nextTheme = currentTheme === "dark" ? "light" : "dark"; htmlEl.setAttribute("data-theme", nextTheme); });
|
JS 操作与媒体查询
鉴于能用 CSS 解决的问题咱就不用 JS 原则,在站点初次加载时,可以优先使用媒体查询的方式获取系统的主题,设置页面的 light/dark 模式,在用户未主动交互前将一直使用这种方式,直到用户主动选择了页面的 light/dark 模式。
用户作出主题选择之后,将为 html 设置 data-theme 属性,此后页面的 light/dark 模式将根据该属性设置。
1 2 3 4 5 6 7
| <script> const theme = localStorage.getItem('theme'); if (theme) { document.documentElement.setAttribute('data-theme', theme); } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| html[data-theme="dark"]:root { --progress-color:linear-gradient(to right, #c2e59c, #64b3f4); --background-color:#1f1f1f; --text-color: #ccc; } html[data-theme="light"]:root { --progress-color:linear-gradient(to right, #c2e59c, #64b3f4); --background-color: #fff; --text-color: #404040; }
@media (prefers-color-scheme: dark) { :root{ --progress-color:linear-gradient(to right, #c2e59c, #64b3f4); --background-color:#1f1f1f; --text-color: #ccc; } } @media (prefers-color-scheme: light) { :root{ --progress-color:linear-gradient(to right, #c2e59c, #64b3f4); --background-color: #fff; --text-color: #404040; } }
|
其他
- theme-color 移动设备浏览器将根据所设定的建议颜色来改变用户界面。
1 2
| <meta name="theme-color" media="(prefers-color-scheme: light)" content="#fff" /> <meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1f1f1f" />
|
- color-scheme 当用户选择其中一种配色方案时,操作系统会对用户界面进行调整。这包括表单控件、滚动条和 CSS 系统颜色的使用值。
如果用户样式表里已经设定了相应的颜色,则会优先应用用户的样式表设置。
1
| <meta name="color-scheme" content="dark light" />
|
参考链接:
一文搞懂前端多主题适配方案