How to Build a Dark Mode Toggle for Your Blog

How to Build a Dark Mode Toggle for Your Blog:

 

https://ift.tt/2UgvLrq

Implementing dark mode

There are multiple ways to do this. I went down the custom properties route. The browser support is pretty good these days, but beware if you need to support older browsers.

We’ll define custom properties for any colours that will need to change when switching between the light and dark themes. These should be accessible from anywhere in the document, so we’ll put them under the :root pseudo-class.

:root {
  --background-color: #f6f6f6;
  --font-color: #222;
  --font-lighter-color: #444;
}
Enter fullscreen mode Exit fullscreen mode

This will be the default theme (light in this case). You can reference these colours using the var(--custom-prop) syntax in your stylesheets. Now, let’s define the dark theme.

:root.dark {
  --background-color: #222;
  --font-color: #f6f6f6;
  --font-lighter-color: #ccc;
}
Enter fullscreen mode Exit fullscreen mode

These properties will override the original ones when we add the dark class to our root element (the  tag). Try doing that manually to see whether the theme changes.


  ...
  ...

Enter fullscreen mode Exit fullscreen mode

Detecting OS-level dark mode setting

Most operating systems come with a setting that allows users to switch between the light and dark versions of the system UI. Some phones even change it automatically based on the time of day or available ambient light.

Fortunately for web devs, there’s a media query to detect just that. We’ll use it to show the dark mode by default for users with their system UI set to dark.

@media (prefers-color-scheme: dark) {
  :root {
    --background-color: #222;
    --font-color: #f6f6f6;
    --font-lighter-color: #ccc;
  }

  :root.light {
    --background-color: #f6f6f6;
    --font-color: #222;
    --font-lighter-color: #444;
  }
}
Enter fullscreen mode Exit fullscreen mode

We’ll also define a new class called light that we’ll use to override the defaults later.

When a user comes to our site, they’ll see a theme based on their OS setting. But they can’t change it yet. For that, we’ll need to build a toggle.

Toggle Switch

To build a simple toggle, we’ll use the old label-and-invisible-checkbox trick. Although it won’t be visible, the checkbox will store the state of our toggle. Using a clever combination of CSS selectors, we’ll be able to control the toggle’s position without adding any JS.

Here’s the HTML:


    
    
Enter fullscreen mode Exit fullscreen mode

When paired with a checkbox, clicking a label is the same as clicking the checkbox itself. This will allow us to change its state despite it being hidden.

Here’s the CSS:

.toggle-switch {
    display: block;
}

#toggle-input {
    display: none;
}

.toggle-switch__control {
    width: 40px;
    height: 14px;
    border-radius: 7px;
    position: relative;

    background: #999;

    cursor: pointer;

    margin: 50px auto;
}

.toggle-switch__control::after {
    content: '';
    display: block;

    width: 20px;
    height: 20px;
    border-radius: 10px;

    position: absolute;
    left: -1px;
    top: -3px;

    background: var(--background-color);

    transition: left 0.25s;
}

#toggle-input:checked + .toggle-switch__control::after {
    left: 21px;
}
Enter fullscreen mode Exit fullscreen mode

The toggle-switch__control div makes up the background track of the switch. The knob on top is an ::after pseudo-element positioned above. We combine the :checked and + CSS selectors to change its position based on the state of the checkbox input. That way, we can avoid using any JS to animate the button.

I also placed an icon next to the toggle that shows which theme is on. See the CodePen at the end of the post for more details.

Switching Themes

First, we’ll define a function called setTheme to switch between the light and dark themes.

function setTheme(theme, persist = false) {
    const on = theme;
    const off = theme === 'light' ? 'dark' : 'light'

    const htmlEl = document.documentElement;
    htmlEl.classList.add(on);
    htmlEl.classList.remove(off);

    if (persist) {
        localStorage.setItem('preferred-theme', theme);
    }
}
Enter fullscreen mode Exit fullscreen mode

The function adds the appropriate class to the document root based on the themeargument. If persist is set, it’ll store the setting in localStorage.

Now, we need to hook setTheme() up to the toggle. We’ll add a listener for the click event on the hidden checkbox.

const toggle = document.getElementById('toggle-input');
const lightIcon = document.getElementById('light-icon');
const darkIcon = document.getElementById('dark-icon');

function updateUI(theme) {
    toggle.checked = theme === 'light';

    if (theme === 'light') {
        lightIcon.classList.add('active');
        darkIcon.classList.remove('active');
    } else {
        darkIcon.classList.add('active');
        lightIcon.classList.remove('active');
    }
}

toggle.addEventListener('click', () => {
    const theme = toggle.checked ? 'light' : 'dark';
    setTheme(theme, true);
    updateUI(theme);
});
Enter fullscreen mode Exit fullscreen mode

Finally, we’ll need to call setTheme() and updateUI() to set the initial theme based on the user’s settings when the page loads up.

const osPreference = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const preferredTheme = localStorage.getItem('preferred-theme') || osPreference;

setTheme(preferredTheme, false);
updateUI(preferredTheme);
Enter fullscreen mode Exit fullscreen mode

The localStorage value takes precedence over the system-wide setting detected via media query. At this point, we set persist to false. We just want to apply the theme without saving the setting. Calling updateUI() will ensure that the toggle is in the right position.

This is it for the dark mode support.

Hiding the Toggle

First, we’ll centre the toggle inside a container and position another one on top using position: absolute. Here’s the HTML:


Enter fullscreen mode Exit fullscreen mode

In the CSS, we’ll position .site-logo__toggle-container and site-logo__logoabsolutely. The toggle container will be slightly smaller and slightly offset (1px) relative to the logo to avoid rendering artefacts around the edges. The --openmodifier will describe the position of the logo when it’s open.

.site-logo {
    width: 125px;
    height: 125px;

    position: relative;
    margin: 40px auto;
}

.site-logo__toggle-container,
.site-logo__logo {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;

    position: absolute;
    border-radius: 50%;
}

.site-logo__toggle-container {
    width: calc(100% - 2px);
    height: calc(100% - 2px);

    top: 1px;
    left: 1px;

    background: var(--font-color);
}

.site-logo__logo {
    background: #ff5857;

    color: white;
    font-weight: bold;

    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

    width: 100%;
    height: 100%;
    border-radius: 50%;

    cursor: pointer;
    transition: all 0.25s;
    left: 0;
}

.site-logo__logo:hover {
    transform: scale(1.03);
}

.site-logo__logo--open {
    left: 85%;
    transform: scale(1.03);
}
Enter fullscreen mode Exit fullscreen mode

Now, let’s give the user the ability to discover the toggle. Because we want the logo to close when the user clicks anywhere else on the page, our setup will be slightly more complicated. We’ll have to attach a listener to window to check whenever the logo should auto-close.

const logo = document.querySelector('.site-logo__logo');
const container = document.querySelector('.site-logo__toggle-container');

function isLogoOpen() {
  return logo.classList.contains('site-logo__logo--open');
}

function autoClose(e) {
  if (isLogoOpen()) {
    const path = e.composedPath();

    /* Close the user clicks outside of the toggle/logo */
    if (path.indexOf(container) < 0 && path.indexOf(logo)  isLogoOpen() ? closeLogo() : openLogo());
Enter fullscreen mode Exit fullscreen mode

The End

That’s everything you need to hide a secret dark mode toggle or another Easter egg on your site. Feel free to use it as it is or experiment and turn it into something completely different!

https://ift.tt/2UgvLrq

from Tumblr https://generouspiratequeen.tumblr.com/post/633218442372268032

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s