A tiny landscape: the sun arcs over the hills and sets while the moon rises on the other side and the sky fades to night. Both ride one rotating arm pinned below the horizon.
Also known as: day to night toggle, sunrise sunset toggle css, landscape theme switch.
<label class="tgl-sunset-toggle">
<input type="checkbox" role="switch" aria-label="Night mode">
<span class="tgl-sunset-toggle-scene" aria-hidden="true">
<span class="tgl-sunset-toggle-night"></span>
<span class="tgl-sunset-toggle-arm">
<span class="tgl-sunset-toggle-sun"></span>
<span class="tgl-sunset-toggle-moon"></span>
</span>
<span class="tgl-sunset-toggle-hills"></span>
</span>
</label>.tgl-sunset-toggle {
--c: var(--tgl-color, #3b82f6);
font-size: var(--tgl-size, 24px);
position: relative;
display: inline-flex;
align-items: center;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.tgl-sunset-toggle input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
z-index: 1;
}
.tgl-sunset-toggle-scene {
position: relative;
display: block;
width: 7.2em;
height: 3.2em;
border-radius: 1.6em;
overflow: hidden;
isolation: isolate;
background: linear-gradient(to bottom, color-mix(in srgb, var(--c) 60%, #bae6fd), #fef3c7);
box-shadow: inset 0 0.1em 0.25em rgba(0, 0, 0, 0.25);
}
.tgl-sunset-toggle-night {
position: absolute;
inset: 0;
background: linear-gradient(to bottom, #0b1026, color-mix(in srgb, var(--c) 35%, #1e1b4b));
opacity: 0;
transition: opacity 0.9s ease 0.1s;
}
.tgl-sunset-toggle-night::before {
content: "";
position: absolute;
top: 0.5em;
left: 2.6em;
width: 0.12em;
height: 0.12em;
border-radius: 50%;
background: #fff;
box-shadow: 0.9em 0.4em 0 #fff, 1.8em -0.1em 0 0.02em #fff, 2.7em 0.6em 0 #fff, 3.5em 0.15em 0 0.02em #fff, 1.2em 1.1em 0 #fff, -1.2em 0.8em 0 #fff;
}
/* the arm pivots under the middle of the horizon */
.tgl-sunset-toggle-arm {
position: absolute;
left: 50%;
top: 4.2em;
width: 0;
height: 0;
transform: rotate(-30deg);
transition: transform 1.1s cubic-bezier(0.55, 0, 0.25, 1);
}
.tgl-sunset-toggle-sun,
.tgl-sunset-toggle-moon {
position: absolute;
border-radius: 50%;
}
.tgl-sunset-toggle-sun {
left: -0.55em;
top: -3.55em;
width: 1.1em;
height: 1.1em;
background: radial-gradient(circle at 40% 40%, #fff7cc, #fcd34d 55%, #f59e0b);
box-shadow: 0 0 0.6em 0.15em rgba(252, 211, 77, 0.6);
}
.tgl-sunset-toggle-moon {
left: -0.5em;
top: 2.5em;
width: 1em;
height: 1em;
background:
radial-gradient(circle at 35% 40%, #cbd5e1 0 0.12em, transparent 0.14em),
radial-gradient(circle at 62% 65%, #cbd5e1 0 0.16em, transparent 0.18em),
#f1f5f9;
box-shadow: 0 0 0.5em 0.05em rgba(241, 245, 249, 0.45);
}
.tgl-sunset-toggle-hills::before,
.tgl-sunset-toggle-hills::after {
content: "";
position: absolute;
height: 3em;
border-radius: 50%;
transition: background-color 0.9s ease;
}
.tgl-sunset-toggle-hills::before {
left: -1.2em;
top: 2.2em;
width: 5.4em;
background-color: #86d99b;
}
.tgl-sunset-toggle-hills::after {
right: -1.5em;
top: 2.45em;
width: 6.2em;
background-color: #3fae63;
}
.tgl-sunset-toggle input:checked + .tgl-sunset-toggle-scene .tgl-sunset-toggle-night { opacity: 1; }
.tgl-sunset-toggle input:checked + .tgl-sunset-toggle-scene .tgl-sunset-toggle-arm { transform: rotate(150deg); }
.tgl-sunset-toggle input:checked + .tgl-sunset-toggle-scene .tgl-sunset-toggle-hills::before { background-color: #23364f; }
.tgl-sunset-toggle input:checked + .tgl-sunset-toggle-scene .tgl-sunset-toggle-hills::after { background-color: #15253a; }
.tgl-sunset-toggle input:focus-visible + .tgl-sunset-toggle-scene {
outline: 2px solid var(--c);
outline-offset: 0.2em;
}
@media (prefers-reduced-motion: reduce) {
.tgl-sunset-toggle, .tgl-sunset-toggle *, .tgl-sunset-toggle::before, .tgl-sunset-toggle::after, .tgl-sunset-toggle *::before, .tgl-sunset-toggle *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--tgl-color on the element or a parent.
Currently previewing #3b82f6.--tgl-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 24px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.