DEV Community

Cover image for Styling a checkbox as darkmode toggle
Dominik
Dominik

Posted on

Styling a checkbox as darkmode toggle

In the first part, we created a checkbox which has the ability to switch our website in darkmode.
In short, we introduced colors, saved in a central SCSS file. With these colors, we created two themes. A dark and a light one. These themes saved the SCSS values as CSS variables.
The checkbox then just switches between the two themes and the variables changing.

Now we want to throw some CSS at our checkbox to make it fun to engage with it. (Nobody wants to click on a small checkbox on their phones)

So we start with HTML structure of the switch like this:

<label class="switch">
  <input type="checkbox" name="theme_switch">
  <span class="slider"></span>
</label>
Enter fullscreen mode Exit fullscreen mode

Now we do a little position and hide the default checkbox:

.switch {
  position: relative;
  display: inline-block;
  width: 68px;
  height: 38px;
  margin: 5px;
}

// hide checkbox
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
Enter fullscreen mode Exit fullscreen mode

After that, we style the outside of the slider:

// outside
.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: grey;
  -webkit-transition: 0.4s;
  transition: 0.4s;
  border-radius: 34px;
}
Enter fullscreen mode Exit fullscreen mode

For the slider element, we use the pseudo-element :before of the slider span.
You can use a normal transition, but I like a slide rubber band animation at the slider. For this, it's best to use a cubic-bezier function. To make this all work, two animations have to be created. One for each direction to slide in. These animations together with the bezier function can be used by the animation property.

So we can style it as follows:

@keyframes going-dark {
  100% {
    -webkit-transform: translateX(28px);
  }
}

@keyframes going-light {
  0% {
    -webkit-transform: translateX(28px);
  }
  100% {
    -webkit-transform: translateX(0px);
  }
}

// slider in light state
.slider:before {
  position: absolute;
  content: '';
  height: 24px;
  width: 24px;
  left: 8px;
  bottom: 7px;
  background-color: white;
  border-radius: 50%;
  -webkit-animation: going-light 0.4s cubic-bezier(0.57, 1.52, 0.64, 1) normal;
  -webkit-transition: 0.4s;
  animation: going-light 0.4s cubic-bezier(0.57, 1.52, 0.64, 1) normal;
  transition: 0.4s;
}

// slider in dark state
input:checked + .slider:before {
  background-color: white;
  -webkit-animation: going-dark 0.4s cubic-bezier(0.57, 1.52, 0.64, 1) forwards;
  -webkit-transition: all 0.4s;
  animation: going-dark 0.4s cubic-bezier(0.57, 1.52, 0.64, 1) forwards;
  transition: all 0.4s;
}
Enter fullscreen mode Exit fullscreen mode

Throw it all together, and you should be able to see something like this:

Discussion (0)