Come to the dark sided theme

2019-09-18

Dark themes are all the rage, people love them! I love them, there is nothing more satisfying than opening an app and having the option to change from light theme to dark, or even matching my phone’s theme. It’s a great experience when it is late night and you open a site or app and its not trying to blind you with its bright white theme.

Today we are going to a talk through how to get a nice dark theme, how to automatically switch based upon someone’s preferences on their machine.

The first thing to talk about is, a great new(ish) Media Query

@media (prefers-color-scheme: dark) {
  // do some stuff.
}

The media query checks to see if the user has dark mode enabled on their device and then does some styling based upon whatever you type in there. What If you just wanted to create a switch, that you could toggle light or dark mode making it work 100% of the time and not waiting for the browsers to catch up.

We will use a button that someone can toggle and than use CSS Variables to handle all the work, it’s quite a simple concept and with a few tweaks to this code you could implement this on your site or web app in minutes.

<nav>
  <div class="theme-switch-wrapper">
       <label class="theme-switch" for="checkbox">
    <input type="checkbox" id="checkbox" />
    <div class="slider round"></div>
  </label>
    <em>Dark Mode</em>
  </div>

</nav>  
<section>
    <article class="post">
      <h1>A Title for your post</h1>
      <p class="post-meta">2019 <span>by</span> The Poster</p>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Interdum posuere lorem ipsum dolor sit amet consectetur. Vitae justo eget magna fermentum iaculis eu non diam phasellus. Pellentesque dignissim enim sit amet venenatis urna cursus eget. Ac tortor vitae purus faucibus ornare. Elit pellentesque habitant morbi tristique senectus. Aliquet risus feugiat in ante metus dictum at. Duis ut diam quam nulla porttitor. Nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Lorem dolor sed viverra ipsum nunc. Eleifend mi in nulla posuere sollicitudin aliquam ultrices sagittis orci. Diam in arcu cursus euismod quis. Est velit egestas dui id.
 <a href="#">Read More</a>
  </article>
</section>

Then the CSS to go with it.

@import url(https://fonts.googleapis.com/css?family=Lato:400,400italic,700|Sansita+One);
  
 :root {
    --primary-color: #302AE6;
    --secondary-color: #536390;
    --font-color: #424242;
    --bg-color: #fff;
    --heading-color: #292922;
}

[data-theme="dark"] {
    --primary-color: #9A97F3;
    --secondary-color: #818cab;
    --font-color: #ffffff;
    --bg-color: #161625;
    --heading-color: #818cab;
}
body {
  font-family: "Lato", sans-serif;
  background-color: var(--bg-color);
  color: var(--font-color);
  max-width: 90%;
  margin: 0 auto;
  font-size: calc(1rem + 0.25vh);
}

h1 {
    color: var(--heading-color);
    font-family: "Sansita One", serif;
    font-size: 2rem;
    margin-bottom: 1vh;
}

p {
  font-size: 1.1rem;
  line-height: 1.6rem;
}

a {
  color: var(--primary-color);
  text-decoration: none;
  border-bottom: 3px solid transparent;
  font-weight: bold;
  &:hover, &:focus {
      border-bottom: 3px solid currentColor;
  }
}

section {
  max-width: 68%;
  margin: 0 auto;
}

.post-meta {
  font-size: 1rem;
  font-style: italic;
  display: block;
  margin-bottom: 4vh;
  color: var(--secondary-color);
}

nav {
  display: flex;
  justify-content: flex-end;
  padding: 20px 0;
}

/*slider switch css */
.theme-switch-wrapper {
  display: flex;
  align-items: center;
  
  em {
    margin-left: 10px;
    font-size: 1rem;
  }
}
.theme-switch {
  display: inline-block;
  height: 34px;
  position: relative;
  width: 60px;
}

.theme-switch input {
  display:none;
}

.slider {
  background-color: #ccc;
  bottom: 0;
  cursor: pointer;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  transition: .4s;
}

.slider:before {
  background-color: #fff;
  bottom: 4px;
  content: "";
  height: 26px;
  left: 4px;
  position: absolute;
  transition: .4s;
  width: 26px;
}

input:checked + .slider {
  background-color: #66bb6a;
}

input:checked + .slider:before {
  transform: translateX(26px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}

Finally We have some javascript

const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
const currentTheme = localStorage.getItem('theme');

if (currentTheme) {
    document.documentElement.setAttribute('data-theme', currentTheme);
  
    if (currentTheme === 'dark') {
        toggleSwitch.checked = true;
    }
}

function switchTheme(e) {
    if (e.target.checked) {
        document.documentElement.setAttribute('data-theme', 'dark');
        localStorage.setItem('theme', 'dark');
    }
    else {        document.documentElement.setAttribute('data-theme', 'light');
          localStorage.setItem('theme', 'light');
    }    
}

toggleSwitch.addEventListener('change', switchTheme, false);

It is quite a simple process to a do a manual toggle, Which you can combine with the media rule so you support both auto detect and manually changing. Maybe a user prefers to read in a light theme but works hard in a dark theme, you can give them the option without having to force theme in to something they don’t want.

Well that is all have on dark theme and detection, implementation. I hope you enjoyed the coverage and implement dark themes on your next project.