Dark-Mode-Umschalter

Als großer Fan von „dunklen Designs“, oder wie man es auch nennt, „Dark Mode“, habe ich ihn in fast allen Apps und Websites umgesetzt, die ich für mich selbst gebaut habe – angefangen bei diesem Blog bis hin zu meinem neuesten Projekt, It Changed.

Mit den Lösungen, die ich im Internet gefunden habe, war ich nicht zufrieden, da sie keinen Schalter mit Media Queries kombinierten. Warum ist das wichtig? Zunächst einmal können Nutzer bereits festgelegte Präferenzen haben. Wählt man beispielsweise unter macOS System Settings >> Appearance >> Dark, wird beim Besuch einer Website (prefers-color-scheme: dark) übergeben. Es kann aber auch Situationen geben, in denen der Nutzer das Theme für eine bestimmte Website auf Hell umschalten möchte.

Um die bestmögliche UX zu bieten, muss es eine Kombination aus mehreren Lösungen sein – was sich, wie Sie gleich sehen werden, gar nicht so schwer umsetzen lässt.

Also, legen wir los.

Umsetzung

Zunächst brauchen wir eine Art Schalter. Für Debugging-Zwecke verwende ich sehr gerne Checkboxen. Hier ein einfaches Beispiel:

<label type="button">
    <input type="checkbox" name="theme-switch" class="theme-switch"/>
    <span>switch</span>
</label>

Kommen wir nun zum JavaScript-Teil:

const themeSwitches = document.querySelectorAll('.theme-switch');
if (themeSwitches.length > 0) {
    themeSwitches.forEach((themeSwitch, i) => {
        if (localStorage.getItem('dark-mode') === 'true') {
            themeSwitch.checked = true;
        } else {
            themeSwitch.checked = false;
        }

        themeSwitch.addEventListener('change', () => {
            const { checked } = themeSwitch;
            themeSwitches.forEach((el, n) => {
                if (n !== i) {
                    el.checked = checked;
                }
            });
            if (themeSwitch.checked) {
                document.documentElement.classList.add('dark');
                localStorage.setItem('dark-mode', true);
            } else {
                document.documentElement.classList.remove('dark');
                localStorage.setItem('dark-mode', false);
            }
        });
    });
}

Dieser Code übernimmt die gesamte Logik des Umschalters und speichert dessen Zustand im localStorage. Da das Element erst nach dem Laden der Seite zugänglich ist, muss dieser Code nicht sofort ausgeführt werden. Es empfiehlt sich, ihn in Ihrer JavaScript-Datei für eine verzögerte Ausführung zu platzieren.

Es gibt jedoch einen Teil des Codes, der tatsächlich so früh wie möglich ausgeführt werden muss. Hier der entsprechende Ausschnitt:

<script>
    if (localStorage.getItem('dark-mode') === 'true' || (!('dark-mode' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
        document.querySelector('html').classList.add('dark');
    } else {
        document.querySelector('html').classList.remove('dark');
    }
</script>

Was dieser Code macht:

  1. Er prüft, ob der Dark Mode im localStorage gesetzt ist;
  2. Enthält localStorage keine Dark-Mode-Einstellung, prüft er, ob der Nutzer den Dark Mode bevorzugt.

Was dadurch sichergestellt wird:

  1. Nutzer erhalten den Dark Mode, wenn sie ihn bei einem früheren Besuch manuell aktiviert haben.
  2. Nutzer erhalten den Dark Mode, wenn ihre Systemeinstellungen zeigen, dass sie ihn bevorzugen.

Design

Da wir den Umschalter als Checkbox umgesetzt haben, eröffnet das ein breites Spektrum an Gestaltungsmöglichkeiten. Er kann als Toggle funktionieren, eine Checkbox bleiben oder sich in einen Button verwandeln – die Möglichkeiten sind nahezu unbegrenzt. Wegen dieser Flexibilität möchte ich hier keine einzelne Gestaltungslösung vorgeben. Wählen Sie die, die am besten zu Ihrem Anwendungsfall passt.

Links

Hier ein paar nützliche Links:

  1. Ich habe diesen Code als Composer-Paket auf Packagist veröffentlicht.
  2. Wenn Sie etwas beitragen möchten, schauen Sie sich das Projekt auf GitHub an.

Das war's, Leute :)