Make Light/Dark mode Toggle for your Website using CSS
Tags: webdev, css, javascript, react
Published: 2021-07-06 19:13:16

Having light and Dark mode on web or desktop applications is a great feature to not only make the user's eyes happier, but to show off some fun and fancy css skills. It gives off an extra level of polish for your personal site if you're using it in a portfolio for a new job. I recently did it on my personal website - but instead of traditional light and dark mode, I changed the colors and themes to be "Light Academia Aesthetic" and "Dark academia Aesthetic".


###Pick Your Colors
First thing first pick your two color palletes for light mode and dark mode. I like to use [coolors.co](https://coolors.co/) to help select colors to get ideas on what to pick. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9iyoyum6cnbxr7611ed.png)

 Now with your hex colors selected we are going to set them as variables in your top .css file. Setting them as variables and then using those variables to assign to individual instances that are using the colors makes for cleaner code, better consistency, and easier updates should you want to change a color.

```
:root {
  /** sunny side **/
  --light-background: #b87e54;
  --light-olive: #4d4828;
  --light-blue: #99c1c3;
  --light-purple: #67597a;
  --light-yellow: #e0cd7e;
  /** dark side **/
  --dark-background: #283618;
  --dark-darkblue: #001d3d;
  --dark-blue: #003566;
  --dark-darkestblue: #000814;
  --dark-mustard: #664e00;
}
```

These colors can then be easily accessed  by calling the variable name you assigned the hex color to `background-color: var(--dark-background);` . 

### Build Your Toggle
For the toggle we are going to build off of an `input` HTML element. This input and its associated label will be turned into something that looks like a toggle with css, but will continue to function the same as a checked, or unchecked, input element. We will be leaning heavily on the `::before` and `::after` [pseudo-elements](https://css-tricks.com/almanac/selectors/a/after-and-before/) to get it done.

```
<input type="checkbox" id="toggle" class="mostHigh toggle--checkbox" />
<label for="toggle" class="toggle--label mostHigh">
</label>
```
We want to hide `.toggle--checkbox` with `display: none` so that the original checkbox isn't visible and then create the toggle outline with `.toggle--label`.

```
.toggle--label {
  width: 80px;
  height: 40px;
  background: var(--blue-color);
  border-radius: 100px;
  border: 5px solid var(--blue-border);
  display: flex;
}
```
We will be using the pseudo-element `::before` to create the switch portion that will toggle back and forth.
```
.toggle--label:before {
  animation-name: reverse;
  animation-duration: 350ms;
  animation-fill-mode: forwards;
  transition: all 350ms ease-in;
  content: "";
  width: 30px;
  height: 30px;
  border: 5px solid var(--yellow-border);
  top: 0px;
  left: 4px;
  position: absolute;
  border-radius: 82px;
  background: var(--yellow-background);
}
```

Now we will be using css [pseudo-class selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes) `:checked' to determine inside the css whether or not the toggle has been clicked on or off. This is very convenient, it prevents having to update the DOM with JavaScript or do conditional rendering.

CSS selectors might have more than one simple selectors and between them we include a combinator. In this toggle we are using an adjacent sibling selector `+` to select the sibling of the class `.toggle--checkbox` (the input) which is `.toggle--label` (the label).  Other combinators for simple selectors are descendant selector (space), a child selector `>` and general sibling selector `~`.


It works in a similar way as `:hover` does, that when that class is checked then the css will update the sibling selectors code. The sibling qualifier is based on the HTML elements to which the classes are assigned.
````
.toggle--checkbox:checked + .toggle--label {
  background: var(--indigo-color);
  border-color: var(--indigo-border);
}

.toggle--checkbox:checked + .toggle--label:before {
  background: var(--white);
  border-color: var(--gray-border);
  animation-name: switch;
  animation-duration: 350ms;
  animation-fill-mode: forwards;
}
````

###Animate the Toggle
Right now the toggle will change colors and move around, and make it visually appear to be toggling. We can do this in css too. We will be using Keyframes for this. Having the keyframes created then assigned to the animation-name attribute that is on `.toggle--label:before`. We are using the keyframes to create visual motion and make the circle toggle move from the left side of the toggle switch to the right - and then back.
````
@keyframes switch {
  0% {
    left: 4px;
  }
  60% {
    left: 20px;
    width: 50px;
  }
  100% {
    left: 40px;
    width: 30px;
  }
}
@keyframes reverse {
  0% {
    left: 24px;
    width: 42px;
  }
  60% {
    left: 20px;
    width: 50px;
  }
  100% {
    left: 4px;
  }
}
````

### Have the Toggle Effect the Site with Day/Night Mode

To push day/night mode to the rest of your site we are going to be using the same process that we used for the `.toggle--label`. We want to make sure that the toggle itself is near the top level so that the header and the main part of the site can be sibling elements to grab on to.

````
<Header />
<Toggle />
<Main />
````

In the way you will be watching to see if the toggle input gets checked, and if so updating the initial css to the toggled css.
````
.header {
  background-color: var(--light-background);
  color: var(--light-olive);
}

.toggle--checkbox:checked ~ .head {
  background-color: var(--dark-background);
  color: var(--white);
}
````

Have fun toggling your different colors around!