- Published on
一个三态按钮的设计、实现
- Authors
- Name
- NickHoo
hugo-book-theme 主题手动切换功能 的思路记录
交接的这几天,整理了一堆文档,正好都集中放在自己内部搭建的文档服务上。文档服务方案是 hugo 引擎 + book 主题。
晚上在暗黑主题的 VS Code 里写 MarkDown,切换到文档服务预览时,纯白色的 book 主题就很刺眼。要是文档也能暗黑模式就好了。采访了一圈组内同事,黑白喜好,一半一半。而我平时是习惯开着Mac系统的亮/暗自动切换,白天全亮,晚上全暗。眼睛确实好受一些。
最后两天闲来无事,那就想办法全都安排上吧。
设计
亮暗主题,本身 book 是都有的,但是只能在部署服务时,写死到配置文件里,要能自由切换得加个功能按钮。但是又不能破坏 book 主题自身的简洁。
那就先确定一下按钮风格:
- 颜色尽量少
- 线条尽量简
按这个要求在图标库里,搜寻一番,一个极简的太阳,一个极简的月亮。下载 svg 矢量图备用。 亮/暗两种模式的图标有了,自动模式的图标找来找去没有心仪的。那就用sketch画一个吧。有先下好的 日月 svg ,原本想的简单组装一下就好。又一个 但是,日月本身都挺好看,放在一起就十分奇怪,可能是 比例不协调。
重新绘制路径、反复调整布局,直到看着比较协调舒适:(挺主观的个人标准。。。)
主题切换时的背景颜色会在黑白间变化,相应亮色主题 图标和文字 为黑色,暗色主题 图标和文字 为白色,自动模式的背景黑白都有可能,于是在自动模式的图标和文字都加入一点淡黄月色。
实现
自动模式标题 实现方式:按对角线左右各一个“auto”,通过 clip-path
来完成对角线切割,但是他俩拼接在一起时,总高度比原先差了一点点,最后又加入一个 正常的“auto” 来撑起高度。这样在文字内容切换时,不会有闪动。
为方便在浏览器内直接调试,先用内联格式来分别指定各自的样式:
<span class="dl_toggle-text-warp">
<span style="
position: relative;
display: inline-block;
">
<span style="
display: inline-block;
font-size: 1rem;
clip-path: polygon(0% 0%, 100% 0%,100% 40%, 0% 70%);
color: #fbe247a6;
position: absolute;">
auto
</span>
<span style="
display: inline-block;
font-size: 1rem;
clip-path: polygon(100% 40%, 100% 100%, 0% 100%,0% 70%);
color: #000;
position: absolute;">
auto
</span>
<span style="background-color: transparent;
display: inline-block;
font-size: 1rem;
clip-path: polygon(100% 30%, 100% 100%, 0% 100%,0% 80%);
color: transparent;
">
auto
</span>
</span>
</span>
切换功能,在js中定义一个简单的三态状态机,点击一次改变一次状态,在 light dark auto 间切换:
// 初始化
// 捕获 页面根元素 用以切换 主题 class
var the_html = document.getElementsByTagName('html')[0]
// 初始化按钮队列
var dl_list = [];
dl_list.push(document.getElementById("dl_toggle_light"))
dl_list.push(document.getElementById("dl_toggle_auto"))
dl_list.push(document.getElementById("dl_toggle_dark"))
var dl_bt = document.getElementById("mode");
var theme = {
mode:null
}
// 读取 历史选择 的主题
theme.mode = localStorage.getItem("theme.mode")===null?null:parseInt(localStorage.getItem("theme.mode"));
// 默认主题
if(theme.mode===null){
theme.mode = 1
}
// 定义 状态机
function toggle_mode(i){
dl_list.forEach((element,index) => {
if (index === i) {
element.style.display = ''
}
else {
element.style.display = 'none'
}
});
switch (i) {
case 0:
the_html.className = 'light'
break;
case 1:
the_html.className = ''
break;
case 2:
the_html.className = 'dark'
break;
default:
break;
}
}
toggle_mode(theme.mode);
// 调用 状态机
function cl_bt (e) {
theme.mode++;
if(theme.mode > 2) {
theme.mode = 0;
}
localStorage.setItem("theme.mode", theme.mode);
toggle_mode(theme.mode)
}
为记住用户的已选主题,将当前主题存入localStorage
。其中有个注意点,localStorage 中的数据是以字符串格式存储的,取出时为方便计算显示转换为整数。parseInt(localStorage.getItem("theme.mode"))
。
效果:
单击按钮,手动指定 light亮/dark暗 文档主题,或者 在 auto自动 模式下,跟随系统主题。