DEV Community

Cover image for CSS Day Night Switch (CSS/HTML only) [PART 2]
crayoncode
crayoncode

Posted on

CSS Day Night Switch (CSS/HTML only) [PART 2]

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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);
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

... which is most importantly the moon's color:

label.day-night-switch {
  > .celestial {
    &.moon {
      background-color: #d2cec4;
      border-color: #a9a18f;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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);
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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);
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

That's all you need to create such a nice little day night swith. I hope you enjoyed creating it.

Top comments (1)

Collapse
 
theeynn profile image
theeynn

This video is private!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
How do I see it??