Dark Mode Support – Real-World PWA: The Making Of Paint.Js.Org – Part 5

In part five of the series about the making of the web-based Microsoft Paint clone paint.js.org, I want to show how to implement support for dark mode in your web applications.

In diesem Artikel:

Dark Mode Support – Real-World PWA: The Making Of Paint.Js.Org – Part 5
Christian Liebel ist Consultant bei Thinktecture. Sein Fokus liegt auf Webstandards und Progressive Web Apps. Er vertritt Thinktecture beim W3C.

Desktop operating systems originally worked with a dark-on-light color scheme. In the meantime, most operating systems have added an option to switch to a light-on-dark scheme, also called dark mode. Especially at night, dark mode is easier on the eyes, and depending on the screen technology, it can even help reduce energy consumption. At around 2019, support for detecting the user’s preference was added to the web platform. The Paint remake also detects if the user is running light or dark mode and adjusts the color scheme user interface accordingly.

Syncing with the Operating System

The prefers-color-scheme CSS media feature indicates which color scheme the user prefers. It can take two values: light, if the user prefers a dark-on-light scheme (or didn’t actively make a decision), and dark, if the user prefers a light-on-dark color scheme instead. Usually, the preference is inherited from the operating system’s settings. If the user’s choice changes during runtime (for example, because the operating system switches between light and dark mode based on time), the change is reflected automatically.

Cascading Through the Shadow DOM

As shown in the first part of this series, the Paint remake makes extensive use of web components: The app itself is a web component, and all its parts, such as the toolbox or color bar, are web components too. All components are using a shadow tree to isolate their style (and structure) from the outside world. However, in the case of paint.js.org, there are values that the components need to share. For instance, the background color („button face“) should only be defined once in the application’s root and reused throughout the rest of the application.

That’s what CSS custom properties are for (or „CSS variables“, as they are sometimes called). In contrast to all the other style definitions, they can be accessed by subordinate components too. The Paint clone defines the colors of Windows 95’s default scheme exactly once at the level of the application’s root node (paint-app). The following is an excerpt of the actual application’s CSS:

				
					:host {
  --button-face: rgb(192 192 192);
  --button-light: white;
  --button-dark: rgb(128 128 128);
  --button-darker: black;
  --button-text: black;
}

				
			

At this central position, we can now re-define the color scheme in case the user prefers a dark color scheme instead. In this case, the custom properties are simply overwritten with different values (i.e., suitable colors for dark mode):

				
					@media (prefers-color-scheme: dark) {
  :host {
    --button-face: rgb(64 64 64);
    --button-light: rgb(128 128 128);
    --button-dark: rgb(32 32 32);
    --button-text: white;
  }
}
				
			

Additional Techniques to Implement Dark Mode

As you can see in the screenshot above, the icons respond to a change of the color scheme as well. I’m using different techniques to achieve this: The toolbox on the left side of the screen shows different parts of one and the same image as the background image of the respective tools. The image used as the background-image is simply swapped with another one containing the icons for dark mode. Other icons of the application, such as the close dialog buttons, are SVGs. For those icons, I’m simply changing the color of their paths.

The prefers-color-scheme media query always resembles the operating system’s setting. If you want to give the user an option to override the setting from within the application, you need to introduce custom CSS classes and set them depending on the user’s choice. By combining the media query and the custom classes, you can start off with the operating system setting and let the user override it during runtime. You can also use the matchMedia() method in JavaScript to listen to changes in the user’s color scheme preference.

As you can see, adding dark mode to your application can be fairly simple. In the case of the Paint remake, there’s no imperative code needed at all. Everything is achieved with the help of the prefers-color-scheme media query and CSS custom properties.

Kostenloser
Newsletter

Aktuelle Artikel, Screencasts, Webinare und Interviews unserer Experten für Sie

Verpassen Sie keine Inhalte zu Angular, .NET Core, Blazor, Azure und Kubernetes und melden Sie sich zu unserem kostenlosen monatlichen Dev-Newsletter an.

Diese Artikel könnten Sie interessieren
Project Fugu
Accessing Files & File Handler – Real-World PWA: The Making Of Paint.Js.Org – Part 4

Accessing Files & File Handler – Real-World PWA: The Making Of Paint.Js.Org – Part 4

In this fourth part of the series about the Microsoft Paint remake on paint.js.org, I want to demonstrate how you can save your drawings to your local disk, read them back later and how to add your web app as a handler for certain file extensions.
12.05.2021
Project Fugu
Copy & Paste Images – Real-World PWA: The Making Of Paint.Js.Org – Part 3

Copy & Paste Images – Real-World PWA: The Making Of Paint.Js.Org – Part 3

In part three of the series about the making of the web-based Microsoft Paint clone paint.js.org, I want to show how you can copy drawings from the Paint clone to other applications and paste them back.
27.04.2021
Project Fugu
Canvas & Input – Real-World PWA: The Making Of Paint.Js.Org – Part 2

Canvas & Input – Real-World PWA: The Making Of Paint.Js.Org – Part 2

After introducing into the project about the web-based Microsoft Paint clone in the first part of this series and talking about the choice of Web Components and the architecture of paint.js.org, I now want to demonstrate how I implemented the drawing functionality.
15.04.2021
Project Fugu
Overview, Web Components & Architecture – Real-World PWA: The Making Of Paint.Js.Org – Part 1

Overview, Web Components & Architecture – Real-World PWA: The Making Of Paint.Js.Org – Part 1

Progressive Web Apps and the new powerful web APIs provided by Project Fugu allow developers to implement desktop-class productivity apps using web technologies. In this six-part article series, Christian Liebel shows you the critical parts of how paint.js.org was made, a web-based clone of the productivity app dinosaur Microsoft Paint. In this first article, Christian gives you an overview of the project, explains the choice of Web Components, and discusses the basic app architecture of the web-based Microsoft Paint clone.
07.04.2021
Angular
From an Angular Web App to a Hybrid App with Capacitor and Ionic Framework

From an Angular Web App to a Hybrid App with Capacitor and Ionic Framework

Creating mobile and desktop applications is a complicated task. Different operating systems require us to have in-depth knowledge of multiple platforms. The web solves most of the problems for us by providing a single platform that runs everywhere - supported by different operating systems and browser vendors. Frameworks like Angular bring the power to write business applications for the web and make a once written application available to everyone.
10.03.2021
Angular
Additional Approaches: Advanced Progressive Web Apps – Push Notifications Under Control – Part 4

Additional Approaches: Advanced Progressive Web Apps – Push Notifications Under Control – Part 4

In the previous parts of this article series, we learned that Apple does not support the standardized web-based push mechanisms, and there is no sign of a possible timeline for implementation. Therefore we have to look at additional ways to bring the users' attention back to our application. Let's use the final article of the series to have a quick look at some approaches that will let us send some form of push message without using the Push API.
15.10.2020