Toggle Night Mode
Der Theme-Toggle ermöglicht das Wechseln zwischen Dark Mode und Light Mode.
Toggle Night Mode
Der Theme-Toggle ermöglicht das Wechseln zwischen Dark Mode und Light Mode. Das gewählte Theme
wird im localStorage gespeichert und über mehrere Tabs
synchronisiert.
Button-Platzierung im Header
Der Theme-Toggle wird im Header zwischen Logo und Mobile-Menu-Button platziert:
<header class="site-header">
<div class="container">
<div class="header-content">
<!-- Logo -->
<div class="brand">...</div>
<!-- Theme Toggle -->
<button class="theme-toggle" id="themeToggle" aria-label="Dark Mode umschalten">
<span class="theme-icon">
<img src="/assets/icons/dark-mode.svg" alt="Copy Icon" width="20" height="20">
</span>
</button>
<!-- Mobile Menu Button -->
<button class="mobile-menu-toggle" id="mobileMenuToggle">...</button>
<!-- Navigation -->
<nav class="main-nav">...</nav>
</div>
</div>
</header>
Wie funktioniert das Theme-System?
Das Theme-System basiert auf dem data-theme Attribut am <html> Element:
- Dark Mode:
<html data-theme="dark">
- Light Mode:
<html data-theme="light">
CSS-Variablen ändern sich automatisch basierend auf dem Theme:
/* Dark Mode (Standard) */
:root {
--bg-primary: #1a1d29;
--text-primary: #e4e6eb;
--accent-blue: #4a9eff;
}
/* Light Mode */
[data-theme="light"] {
--bg-primary: #ffffff;
--text-primary: #1a1d29;
--accent-blue: #0066cc;
}
Icon-Logik: Warum wechselt das Icon?
Das Icon zeigt immer das andere Theme an (nicht das aktuelle!):
- Im Dark Mode: Zeige Light-Icon → "Klick mich für Light Mode"
- Im Light Mode: Zeige Dark-Icon → "Klick mich für Dark Mode"
Das ist intuitiver als ein Icon, das den aktuellen Zustand zeigt.
Wie funktioniert das technisch?
Die Magie passiert in der updateThemeIcon()-Funktion. Der
entscheidende Trick ist diese Zeile:
// Das "umgekehrte" Icon wählen:
const iconSrc = theme === 'dark' ? THEME_ICONS.light : THEME_ICONS.dark;
Der ternäre Operator ? : prüft:
"Ist das aktuelle Theme dark? Dann nimm das light-Icon, sonst das dark-Icon."
Die vollständige Funktion und wie sie mit dem Click-Event zusammenspielt, findest du weiter unten im vollständigen JavaScript-Code.
Icon-Pfade definieren
Die Icon-Pfade werden am Anfang des JavaScripts definiert:
const THEME_ICONS = {
dark: '/assets/icons/light-mode.svg', // Im Dark Mode: zeige Sonne → "Wechsel zu Light"
light: '/assets/icons/dark-mode.svg' // Im Light Mode: zeige Mond → "Wechsel zu Dark"
};
Eigene Icons verwenden
Wichtig bei der Auswahl eigener Icons:
- Form: Icons sollten quadratisch oder rund sein (1:1 Verhältnis)
- Größe: 20x20px oder 24x24px (viewBox anpassen)
- Format: SVG bevorzugt (für scharfe Darstellung)
- Style: Einfache, klare Symbole (Mond/Sonne, Toggle, etc.)
Probleme mit anderen Icon-Formen:
- Slider/Switch-Icons (rechteckig) passen nicht in den runden Button
- Der Button hat eine
border-radius, die bei nicht-quadratischen Icons stört - Rechteckige Icons werden gequetscht oder verzerrt
Um eigene Icons zu verwenden:
- Platziere deine Icons in
/assets/icons/ - Benenne sie z.B.
mond.svgundsonne.svg - Aktualisiere die Pfade im JavaScript:
const THEME_ICONS = {
dark: '/assets/icons/sonne.svg', // Im Dark Mode: zeige Sonne
light: '/assets/icons/mond.svg' // Im Light Mode: zeige Mond
};
Theme-Speicherung & Persistenz
Das gewählte Theme wird automatisch im localStorage gespeichert:
- Beim Laden: Das zuletzt gewählte Theme wird wiederhergestellt
- Standard: Wenn kein Theme gespeichert ist, wird Dark Mode verwendet
- Tab-Synchronisation: Theme-Wechsel in einem Tab werden in allen anderen Tabs übernommen
Vollständiger JavaScript-Code
// ===================================
// THEME TOGGLE (Dark/Light Mode) mit Icon-Wechsel
// ===================================
const themeToggle = document.getElementById('themeToggle');
const currentTheme = localStorage.getItem('theme') || 'dark';
// Setze initial Theme
document.documentElement.setAttribute('data-theme', currentTheme);
// Funktion: Icon aktualisieren basierend auf aktuellem Theme
function updateThemeIcon(theme) {
if (!themeToggle) return;
// Finde das img Element innerhalb des Buttons
const img = themeToggle.querySelector('.theme-icon img');
if (!img) return;
// Dark Mode = zeige Light Icon (zum Wechseln zu Light)
// Light Mode = zeige Dark Icon (zum Wechseln zu Dark)
const iconSrc = theme === 'dark' ? THEME_ICONS.light : THEME_ICONS.dark;
img.src = iconSrc;
// Accessibility: Aria-Label aktualisieren
const label = theme === 'dark' ? 'Zu Light Mode wechseln' : 'Zu Dark Mode wechseln';
themeToggle.setAttribute('aria-label', label);
}
// Initial Icon setzen
updateThemeIcon(currentTheme);
if (themeToggle) {
themeToggle.addEventListener('click', () => {
const current = document.documentElement.getAttribute('data-theme');
const newTheme = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
// Icon aktualisieren
updateThemeIcon(newTheme);
console.log(`🌓 Theme gewechselt: ${current} → ${newTheme}`);
});
}
// Theme synchronisieren bei Tab-Wechsel
window.addEventListener('storage', (e) => {
if (e.key === 'theme') {
const newTheme = e.newValue || 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
updateThemeIcon(newTheme);
}
});
Standard-Theme ändern
Um Light Mode als Standard zu verwenden (statt Dark Mode):
// Ändere 'dark' zu 'light'
const currentTheme = localStorage.getItem('theme') || 'light';
Button-Styling anpassen
Das Styling des Theme-Toggle-Buttons findest du in style.css unter
"Header & Navigation":
.theme-toggle {
background: transparent;
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 0.5rem;
cursor: pointer;
transition: all 200ms ease;
}
.theme-toggle:hover {
background-color: var(--bg-secondary);
border-color: var(--accent-blue);
}
.theme-icon img {
display: block;
width: 20px;
height: 20px;
}
Icon-Probleme lösen
Wenn du Slider/Toggle-Icons (rechteckige Form, z.B. 40x20px) verwendest, wird oft nur eine Ecke angezeigt. Das liegt am CSS:
/* Aktuelles CSS (für quadratische Icons) */
.theme-icon img {
display: block;
width: 20px; /* ← Erzwingt 20px Breite */
height: 20px; /* ← Erzwingt 20px Höhe */
}
Was passiert:
- Ein 40x20px Icon wird auf 20x20px gequetscht
- Der Browser zeigt nur den linken Teil (erste 20px Breite)
- Der Rest wird abgeschnitten → Nur eine Ecke sichtbar
Lösung 1: CSS für rechteckige Icons anpassen
Um Slider-Icons korrekt anzuzeigen, muss das CSS geändert werden:
/* Für Slider-Icons (rechteckig, z.B. 40x20px) */
.theme-icon img {
display: block;
width: auto; /* ← Breite automatisch */
height: 20px; /* ← Nur Höhe fixieren */
max-width: 50px; /* ← Maximale Breite begrenzen */
object-fit: contain; /* ← Seitenverhältnis beibehalten */
}
Oder für mehr Kontrolle:
/* Für Slider-Icons - spezifische Größe */
.theme-icon img {
display: block;
width: 40px; /* ← Breite des Sliders */
height: 20px; /* ← Höhe des Sliders */
object-fit: contain; /* ← Wichtig! */
}
Lösung 2: Button-Container anpassen
Der Button selbst muss auch breiter werden, um den Slider aufzunehmen:
.theme-toggle {
background: transparent;
border: 1px solid var(--border-color);
border-radius: 12px; /* ← Mehr Radius für rechteckige Form */
padding: 0.4rem 0.6rem; /* ← Mehr horizontales Padding */
cursor: pointer;
transition: all 200ms ease;
/* Optional: */
min-width: 50px; /* ← Mindestbreite für Slider */
}
Auch mit angepasstem CSS gibt es Probleme:
- Design-Inkonsistenz: Der Button wird rechteckig und passt nicht zu den anderen runden Buttons im Header
- Border-Radius stört: Die abgerundeten Ecken passen nicht zur rechteckigen Icon-Form
- Responsive Probleme: Auf mobilen Geräten nimmt der breitere Button mehr Platz weg
- Visuelle Hierarchie: Ein breiterer Button zieht mehr Aufmerksamkeit als gewünscht
Empfohlene Alternative zu Slider-Icons
Statt Slider-Icons funktionieren diese Varianten besser:
Gut: Mond/Sonne Icons
- Quadratisch (z.B. 20x20px)
- Klare Symbole
- Universell verständlich
Gut: Toggle-Kreis Icons
- Rund (Durchmesser 20px)
- Ein/Aus Symbol
- Minimalistisch
Problematisch: Slider/Switch
- Rechteckig (z.B. 40x20px)
- Benötigt mehr Platz
- Passt nicht in runden Button
Problematisch: Text-Icons
- Zu groß/breit
- Nicht responsive-freundlich
- Lokalisierungsprobleme
Bonus: SVG viewBox richtig einstellen
Wenn dein Icon trotz korrektem CSS abgeschnitten wird, prüfe den viewBox im SVG:
<!-- Falscher viewBox (zeigt nur Ecke) -->
<svg viewBox="0 0 20 20" width="40" height="20">
<!-- Icon ist 40x20, aber viewBox ist 20x20 → abgeschnitten! -->
</svg>
<!-- Richtiger viewBox (zeigt alles) -->
<svg viewBox="0 0 40 20" width="40" height="20">
<!-- viewBox passt zu tatsächlicher Icon-Größe ✓ -->
</svg>
Regel: Der viewBox muss zur tatsächlichen
Zeichenfläche des Icons passen!
Mehr aus DevPanicZone!
Tutorials werden geladen...