Now let's get this finished by implementing the night state of our nice day-night-switch by implementing a moon, day-night transitions and a few sparkling stars as a bonus.
Read the full article or watch me code this on Youtube:
Result
Turning off the lights
So, let's start by turning off the lights, which means that as soon as the switch is unchecked, the background color as well as the border color fade to a darker tone of blue.
input.day-night-switch {
// unchecked styles
+ label.day-night-switch {
border-color: #2a4569;
background-color: #223349;
}
}
Since also everything appears darker at night (who would have thought...), the mountains also fade from a lighter gray to a darker one, as soon as the checkbox is unchecked.
input.day-night-switch {
// unchecked styles
+ label.day-night-switch {
> .mountains {
> * {
background-color: #878787;
border-color: #5c5c5c;
}
}
}
}
Sunset
First let's define a position to which sun and moon are shifted as soon as they need to set. In this case sun and moon are going to shifted 25% of the height below the lower edge, i.e. 1.25 x the height of the entire switch.
input.day-night-switch {
--shift: calc(var(--height) * 1.25);
}
Now, to make the sun set, we simply update its value for the top
property as soon as the checkbox is unchecked. Additionally it is scaled down to 0
to create a little bit of a stronger sunset effect.
input.day-night-switch {
// unchecked styles
+ label.day-night-switch {
> .celestial {
&.sun {
transition-delay: 0ms;
top: var(--shift);
left: var(--pos-right);
transform: scale(0);
}
}
}
}
Let the moon come out!
Now that the sun is able to come and go, there's space for the moon. Therefore let's put a div
with the celestial
class for the shared styling of sun and moon and the moon
class for the moon-specific styling...
label(for="day-night").day-night-switch
...
div.celestial.moon
... which is most importantly the moon's color:
label.day-night-switch {
> .celestial {
&.moon {
background-color: #d2cec4;
border-color: #a9a18f;
}
}
}
Analogously to the sun, the moon gets also set its coordinates to where it should be during daytime (checked) and nighttime (unchecked):
input.day-night-switch {
// checked styles
&:checked {
+ label.day-night-switch {
> .celestial {
&.moon {
transition-delay: 0ms;
left: var(--pos-left);
top: var(--shift);
transform: scale(0);
}
}
}
}
}
input.day-night-switch {
// unchecked styles
+ label.day-night-switch {
> .celestial {
&.moon {
transition-delay: var(--transition-duration);
top: var(--padding);
left: var(--pos-left);
overflow: hidden;
transform: scale(1);
}
}
}
}
Craters!
However, the moon looks still a little but dull and boring and actually not really like a moon. To fix this, let's add a few craters:
label(for="day-night").day-night-switch
...
div.celestial.moon
div.craters
div.crater
div.crater
div.crater
div.crater
div.crater
Very similar to the clouds the craters are positioned relatively to the --switch-size
inside the moon. Each crater is in the end just a div
which is made a circle through border-radius: 50%
.
The border width of each crater is set to to slightly smaller value than the border width of the moon. But it should never be smaller than 1px
, which is achieved by using the max(...)
function, returning always the largest value of the ones which are passed to it. So should 65% of the --border-width
be ever the smaller one, 1px
is returned.
label.day-night-switch {
> .celestial {
&.moon {
> .craters {
> .crater {
background-color: #d2cec4;
border-color: #a9a18f;
border-width: calc(max(var(--border-width) * 0.65, 1px));
border-style: solid;
position: absolute;
&:nth-child(1) {
border-radius: 50%;
width: calc(var(--switch-size) * 0.15);
height: calc(var(--switch-size) * 0.15);
top: calc(var(--switch-size) * 0.7);
left: calc(var(--switch-size) * 0.4);
}
&:nth-child(2) {
border-radius: 50%;
width: calc(var(--switch-size) * 0.3);
height: calc(var(--switch-size) * 0.3);
top: calc(var(--switch-size) * 0.1);
left: calc(var(--switch-size) * -0.05);
}
&:nth-child(3) {
border-radius: 50%;
width: calc(var(--switch-size) * 0.1);
height: calc(var(--switch-size) * 0.1);
top: calc(var(--switch-size) * 0.2);
left: calc(var(--switch-size) * 0.6);
}
&:nth-child(4) {
border-radius: 50%;
width: calc(var(--switch-size) * 0.1);
height: calc(var(--switch-size) * 0.1);
top: calc(var(--switch-size) * 0.3);
left: calc(var(--switch-size) * 0.25);
}
&:nth-child(5) {
border-radius: 50%;
width: calc(var(--switch-size) * 0.2);
height: calc(var(--switch-size) * 0.2);
top: calc(var(--switch-size) * 0.5);
left: calc(var(--switch-size) * 0.8);
}
}
}
}
}
}
Sparkling stars
Now finally, let's make this night sky perfectly clear by adding a few sparking stars. The good thing is that we already have a few .decoration
elements for the clouds in the DOM that we don't need at night time. So let's simply reuse them for the stars and by that creat
input.day-night-switch {
// unchecked styles
+ label.day-night-switch {
> .decorations {
> .decoration {
position: absolute;
background-color: white;
border-radius: 50%;
width: calc(max(var(--border-width) * 0.75, 2px));
height: calc(max(var(--border-width) * 0.75, 2px));
animation: 2s sparkle ease-in-out infinite;
animation-direction: alternate;
&:nth-child(1) {
top: calc(var(--switch-size) * 0.7);
left: calc(var(--switch-size) * 1.7);
}
&:nth-child(2) {
animation-delay: 300ms;
animation-duration: 3s;
top: calc(var(--switch-size) * 0.4);
left: calc(var(--switch-size) * 1.4);
}
&:nth-child(3) {
animation-delay: 800ms;
animation-duration: 3.5s;
top: calc(var(--switch-size) * 0.9);
left: calc(var(--switch-size) * 2.2);
}
&:nth-child(4) {
animation-delay: 1400ms;
animation-duration: 2.5s;
top: calc(var(--switch-size) * 0.3);
left: calc(var(--switch-size) * 2);
}
}
}
}
}
The sparkling animation itself is just going to alternate between 100% and 25% of opacity for each star:
@keyframes sparkle {
0% {
opacity: 1;
}
100% {
opacity: 0.25;
}
}
input.day-night-switch {
// unchecked styles
+ label.day-night-switch {
> .decorations {
> .decoration {
transition: all var(--transition-duration) ease-in-out;
animation: 2s sparkle ease-in-out infinite;
animation-direction: alternate;
}
}
}
}
To make the sparkling a little bit more exciting, different delays and duration are applied to each star...aaaand it's done!
// unchecked styles
+ label.day-night-switch {
> .decorations {
> .decoration {
&:nth-child(2) {
animation-delay: 300ms;
animation-duration: 3s;
}
&:nth-child(3) {
animation-delay: 800ms;
animation-duration: 3.5s;
}
&:nth-child(4) {
animation-delay: 1400ms;
animation-duration: 2.5s;
}
}
}
That's all you need to create such a nice little day night swith. I hope you enjoyed creating it.