日夜切换开关
一个支持日夜模式切换的开关组件。活跃状态下为胶囊条,静止时为圆点。采用拟态风格设计
<label class="theme-switch" title="切换日夜模式">
<input type="checkbox" class="theme-toggle-input">
<span class="slider-track"></span>
<span class="slider-dot">
<span class="icon sun"></span>
<span class="icon moon"></span>
</span>
</label>
/* 1. 总容器 */
.theme-switch {
position: relative;
display: block;
width: 60px;
height: 34px;
cursor: pointer;
transition: none;
}
.theme-switch input {
opacity: 0;
width: 0;
height: 0;
}
/* 2. 背景轨道 */
.slider-track {
position: absolute;
top: 0; left: 0;
width: 34px; height: 34px;
border-radius: 17px;
box-shadow: inset 2px 2px 4px rgba(0,0,0,0.2), inset -2px -2px 4px rgba(255,255,255,0.05);
transition: width 0.3s ease, left 0.3s ease, border-radius 0.3s ease, box-shadow 0.3s ease;
background-color: var(--switch-track-bg, var(--surface-container-highest));
}
.theme-switch:hover .slider-track { width: 60px; }
.theme-switch input:checked + .slider-track { left: 26px; }
.theme-switch:hover input:checked + .slider-track { left: 0; }
/* 3. 滑块圆点 */
.slider-dot {
position: absolute;
height: 26px; width: 26px;
left: 4px; top: 4px;
border-radius: 50%;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.3s ease, box-shadow 0.3s ease;
background-color: var(--switch-dot-bg, var(--primary));
}
.theme-switch input:checked ~ .slider-dot {
transform: translateX(26px);
background-color: var(--switch-dot-checked-bg, var(--primary-container));
}
/* 4. 图标样式 (核心修改) */
.slider-dot .icon {
position: absolute;
width: 20px; height: 20px;
-webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
-webkit-mask-position: center; mask-position: center;
-webkit-mask-size: contain; mask-size: contain;
transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background-color: var(--switch-icon-color, var(--on-primary));
}
.icon.sun { -webkit-mask-image: url('/icons/sun.svg'); mask-image: url('/icons/sun.svg'); }
.icon.moon { -webkit-mask-image: url('/icons/moon.svg'); mask-image: url('/icons/moon.svg'); }
/* 控制动画和显隐 */
.sun { opacity: 1; transform: translateY(0) rotate(0deg); }
.moon { opacity: 0; transform: translateY(20px) rotate(-45deg); }
input:checked ~ .slider-dot .sun { opacity: 0; transform: translateY(-20px) rotate(45deg); }
input:checked ~ .slider-dot .moon {
opacity: 1;
transform: translateY(0) rotate(0deg);
background-color: var(--switch-icon-checked-color, var(--on-surface));
}
<!-- sun.svg -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><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>
<!-- moon.svg -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>