Hit the switch to change into night viewing mode

If you’re anything like me, you probably use the web long after midnight, or after waking from sleep to check something on your phone. Modern LED screens put out a lot of artificial light, a technology that human perceptual systems have yet to adapt to. In particular, mobile devices pump out blue-tinted light, fooling our eyes (and thus our brains) into believing it is “day”. This suppresses melatonin levels, which in turn makes sleep more difficult.

As modern web developers it behooves us to make our sites as adaptive as possible to the user’s environment, which includes taking into account late nights, tired eyes, and need for restful sleep. We can do this with a fairly simple alteration to our stylesheets, and a bit of JavaScript.

After Midnight

First, we need to determine the conditions for a night-adaptive page change. The user could be in one of several possible situations:

  1. Using the web after sunset, or before sunrise
  2. Trying to use their screen in a dim environment
  3. They could be photophobic (sensitive to bright light)

The first two we can know, or at least make educated guesses for, while cues for the latter currently have to come from the user. That means we must have both manual and automatic control over “night vision” mode.

The simplest automatic method is to detect the local time of day, and use that to add a class to the root <html> element:

var currentTime = new Date().getHours();

function timeCheck() {
    if (currentTime > 18 || currentTime < 6) {
      document.documentElement.classList.add('night');
    }
}
timeCheck();

Day For Night

In principle, switching the majority of sites - which feature black text on a white background - into a “night vision” mode would simply be a case of inverting the page colors. We have a CSS filter to do just that:

.night { filter: invert(100%); }

Unfortunately, the result is not what you might expect: the filter does not change the background color of the page:

Adding an inverse filter does not affect the background of the page, and degrades most images

That means we must treat page elements separately for night vision mode. Thankfully, the job isn’t too hard. We must:

  1. Swap the background of the page to something dark.
  2. Switch the text to an appropriate light color, making sure that it keeps an appropriate contrast ratio.
  3. Black-and-white images should probably be inverted, but others (such as color photographs) should be left alone.

I’ll write the new styles in Sass for clarity, but it could be done in vanilla CSS almost as easily:

.night {
    body { 
        background: #000; 
        color: #fff;
    }
}

For images, you have one of two choices. If a minority of images on the page need to be color-inverted, you could provide them with a special class. For example, this autograph of Jules Verne would look correct when inverted, as shown in the demo: Autograph of Jules Verne

Adding the class to the code:

<img src="jules-verne-autograph.svg" alt="Jules Verne" class="switch">

And the SASS is added to:

.night {
    body { 
        background: #000; 
        color: #fff;
    }
    img.switch { 
        filter: invert(100%);
    }
}
Diagram of Earth-Moon-Sun system
Inverting this picture would make the sun black, so it must be shielded from any change

Alternatively, if the majority of your images needed to be switched, you could protect those that should not be affected, like this picture:

Adding a class of protected:

<img src="earth-moon-sun-system.png" class="protected" 
alt="Diagram of Earth-Moon-Sun system">

And then using the :not pseudo-selector to only change those images that were not protected by the class:

img:not(.protected) { 
    filter: invert(100%);
}

To smooth out the color shift when the time changes, add a transition to the body in the base CSS, restricted to the properties that are modified during the transition to night mode:

body { 
        transition: 2s background, color;
}

Good Day, Sunshine

Right now the time detection script runs just once: that is, if the user opens the page at 1am, it will always remain that time to the script.

If it was reasonable to assume that the page might be left open in a tab all night, you might want to recheck the time every hour, and reset the page mode then:

function callEveryHour() {
    setInterval(timeCheck(), 1000 * 60 * 60);
}

Good Night

This takes care of simple automatic changes to site styles, at least at a basic level. You may have noticed that I did not employ this particular set of techniques in this article, to avoid confusion; in addition, the color changes are not persistant as you navigate across the site. I’ll be talking about the manual method, and making the color changes stick, in the next articles.

As this article went live I became aware of a problem with changing the background in IOS 9.2 on iPhone models (but curiously, not on iPad). I'll provide a solution to that issue today.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/LGpjgm