由于写一个基于 Remix + Mdx 的博客项目,其中探索的 web 端的暗黑模式做法。总结成一点:
自动:
CSS 变量
切换与CSS 媒体查询
。
手动:
CSS 变量
切换与JS 交互
。
基础知识
- prefers-color-scheme 媒体查询
@media (prefers-color-scheme: dark) {
/* 暗黑模式下的样式 */
}
@media (prefers-color-scheme: light) {
/* 亮色模式下的样式 */
}
- 特殊的 color-scheme 属性
操作系统颜色方案的常见选择为“亮色”和“暗色”,或“日间模式”和“夜间模式”。当用户选择其中一种颜色方案时,操作系统会对用户界面进行调整,包括表单控件、滚动条和 CSS 系统颜色的使用值。
color-scheme: normal; // 未指定任何配色方案,因此应使用浏览器的默认配色方案呈现
color-scheme: light; // 使用操作系统亮色配色方案渲染元素
color-scheme: dark; // 使用操作系统深色配色方案渲染元素
color-scheme: light dark; // 要将整个页面配置为使用用户的配色方案首选项
color-scheme: only light; // 禁止用户代理覆盖元素的颜色方案, 仅仅使用 light
除了 css 变量还要关注哪些问题?
- 可访问性 Accessibility) 在安和模式中可访问性更多的关注
颜色
可见性。 - 颜色切换动画, 以下是一个简单的实现:
body {
transition: background-color 0.3s ease;
}
一个最简单的暗黑模式
@media (prefers-color-scheme: dark) {
html {
filter: invert(90%) hue-rotate(180deg); // 颜色反转 90%, 色相旋转 180 deg
}
img, video, svg, div[class*="language-"] {
// 对图片,视频, svg 和 div 中 language- 开头的类,反转 110% 度。
filter: invert(110%) hue-rotate(180deg);
opacity: .8;
}
}
最简单的样式只关注 css 部分,随系统控制样式变化。
一个最简单手动挡 js 运行时
媒体查询
使用 vite 初始化一个 原生 TS 项目,添加按钮,实现简单的 浏览器 js 运行时中切换亮色和暗色
:
- 添加 html
<div class="schema-mode">
<button id="change-mode-id" type="button">change 颜色</button>
</div>
- 添加 js 交互代码
export function changeSchemaMode(element: HTMLButtonElement) {
const setMode = () => {
const html = document.documentElement.getAttribute("class");
console.log(html);
if (!html) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
};
element.addEventListener("click", () => setMode());
}
- 添加 css 代码
:root {
--bg: #fff;
}
html.dark {
color-scheme: dark;
}
.dark {
--bg: #272020;
}
body {
margin: 0;
min-height: 100vh;
background-color: var(--bg);
}
点击按钮切换按钮实现 css 颜色的切换。这种方式缺点也很明显,刷新之后页面不能保留状态。
保留暗黑模式状态
在实现配合框架中实现暗黑模式的时候,可能我们问题会发生转移,变成如何存储 暗黑模式 交互式产生的变量。本质上使用纯 css 变量 + css 媒体查询,使用的是,系统的变量(随系统的变量的变化而变化。)
渲染方式 | 说明 | 结果 |
---|---|---|
客户端渲染 | js 运行时修改 | 刷新即消失,体验不好 |
客户端渲染 | js 运行时 + 本地存储同步状态 | 体验良好 |
ssr | js 运行时 | 刷新即消失 |
ssr | js 运行时 + cookie + session 辅助 | 体验良好 |
ssr | js 运行时 + localstorage | 页面闪动 |
以下 Remix 中使用 session + cookie 存储的页面变化,实现的暗色模式。
但这里其实实现暗色模式其实已经需要前后端配合,前后将选择的 theme 保存在 session + cookie 中存储起来。来保证页面不会闪动。
其他的:灰色模式
灰色模式使用滤镜模式实现,用于一些特定的样式技巧。
html{
-webkit-filter : grayscale(100%);
-moz-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: grayscale(100%);
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
}
css 滤镜注意使用 css 的兼容性。
项目推荐
- remix-mdx-blog 中实践了 Remix 框架的诸多技巧, Remix 目前并不流行,但是 Remix 是一个好的全栈框架,目前正处于向 V2 版本的开发之中。其中暗黑模式操作使用与 Remix 框架,如果你对小技术的变化演进感兴趣,不妨尝试,如果能帮助到你,不妨给个 star 或者请作者喝一杯奶茶。
小结
这篇文章主要讲解 css 关注暗黑模式的探索,最简单的暗黑模式,手动控制不同的样式,以及可访问性(颜色的可访问性),在 vite + 原生 TS 项目中实现手动暗黑模式切换。有了这些基础实现一个小的暗黑模式难度就不到的,后面是集成到现在带有 SSR 渲染框架中,因为像 React 中 SSR 存在水合的过程,使用 本地存储,保存状态会存在山东等问题,本地存储不适合 SSR 的框架,所以存储方式改为 session + cookie 的方式,说白就是存到了服务端保证SSR 渲染出 html 的时候, html 属性中带有正确的属性,不至于水合的过程发生变化。
原文链接:https://juejin.cn/post/7238185960058929211 作者:进二开物