SCSS Dark Mode - Theme Switching
Lerne wie du professionelles Dark Mode mit SCSS implementierst.
Strategie 1: CSS Custom Properties
Variables definieren
// _themes.scss
:root {
// Light Theme (Default)
--color-background: #ffffff;
--color-surface: #f5f5f5;
--color-text-primary: #1a1a1a;
--color-text-secondary: #666666;
--color-border: #e0e0e0;
--color-primary: #007bff;
--color-primary-hover: #0056b3;
}
[data-theme="dark"] {
// Dark Theme
--color-background: #1a1a1a;
--color-surface: #2d2d2d;
--color-text-primary: #ffffff;
--color-text-secondary: #b0b0b0;
--color-border: #404040;
--color-primary: #4d9fff;
--color-primary-hover: #7db3ff;
}
Usage in Components
.card {
background: var(--color-surface);
color: var(--color-text-primary);
border: 1px solid var(--color-border);
padding: 1rem;
border-radius: 8px;
&__title {
color: var(--color-text-primary);
}
&__description {
color: var(--color-text-secondary);
}
}
.button {
background: var(--color-primary);
color: white;
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
&:hover {
background: var(--color-primary-hover);
}
}
Strategie 2: SCSS Mixins
// _themes-mixin.scss
@mixin light-theme {
--color-background: #ffffff;
--color-text: #000000;
}
@mixin dark-theme {
--color-background: #1a1a1a;
--color-text: #ffffff;
}
// Apply
:root {
@include light-theme;
}
[data-theme="dark"] {
@include dark-theme;
}
Strategie 3: SCSS Maps
// _color-palette.scss
$themes: (
light: (
background: #ffffff,
surface: #f5f5f5,
text-primary: #1a1a1a,
text-secondary: #666666,
border: #e0e0e0,
primary: #007bff,
success: #28a745,
warning: #ffc107,
error: #dc3545
),
dark: (
background: #1a1a1a,
surface: #2d2d2d,
text-primary: #ffffff,
text-secondary: #b0b0b0,
border: #404040,
primary: #4d9fff,
success: #4caf50,
warning: #ffb300,
error: #f44336
)
);
// Function to get theme color
@function theme-color($theme, $color) {
@return map-get(map-get($themes, $theme), $color);
}
// Generate CSS Variables
:root {
@each $color, $value in map-get($themes, light) {
--color-#{$color}: #{$value};
}
}
[data-theme="dark"] {
@each $color, $value in map-get($themes, dark) {
--color-#{$color}: #{$value};
}
}
prefers-color-scheme
Automatische Erkennung der System-Präferenz:
// Default: Light Theme
:root {
--color-background: #ffffff;
--color-text: #000000;
}
// Dark Theme wenn System Preference
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--color-background: #1a1a1a;
--color-text: #ffffff;
}
}
// Explizite Theme-Auswahl überschreibt System
[data-theme="light"] {
--color-background: #ffffff;
--color-text: #000000;
}
[data-theme="dark"] {
--color-background: #1a1a1a;
--color-text: #ffffff;
}
Complete Theme System
// abstracts/_themes.scss
$color-schemes: (
light: (
// Backgrounds
bg-primary: #ffffff,
bg-secondary: #f8f9fa,
bg-tertiary: #e9ecef,
// Text
text-primary: #212529,
text-secondary: #6c757d,
text-tertiary: #adb5bd,
text-inverse: #ffffff,
// Borders
border-light: #e9ecef,
border-medium: #dee2e6,
border-dark: #ced4da,
// Brand
primary: #0d6efd,
primary-hover: #0b5ed7,
success: #198754,
warning: #ffc107,
error: #dc3545,
info: #0dcaf0,
// Shadows
shadow-sm: rgba(0, 0, 0, 0.075),
shadow-md: rgba(0, 0, 0, 0.15),
shadow-lg: rgba(0, 0, 0, 0.25)
),
dark: (
// Backgrounds
bg-primary: #212529,
bg-secondary: #2b3035,
bg-tertiary: #343a40,
// Text
text-primary: #f8f9fa,
text-secondary: #adb5bd,
text-tertiary: #6c757d,
text-inverse: #212529,
// Borders
border-light: #495057,
border-medium: #343a40,
border-dark: #2b3035,
// Brand
primary: #0d6efd,
primary-hover: #3d8bfd,
success: #198754,
warning: #ffc107,
error: #dc3545,
info: #0dcaf0,
// Shadows
shadow-sm: rgba(0, 0, 0, 0.3),
shadow-md: rgba(0, 0, 0, 0.5),
shadow-lg: rgba(0, 0, 0, 0.7)
)
);
// Generate CSS Variables
@mixin generate-theme($theme-name) {
$theme: map-get($color-schemes, $theme-name);
@each $key, $value in $theme {
--#{$key}: #{$value};
}
}
// Apply Themes
:root {
@include generate-theme(light);
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
@include generate-theme(dark);
}
}
[data-theme="light"] {
@include generate-theme(light);
}
[data-theme="dark"] {
@include generate-theme(dark);
}
// Usage in Components
.card {
background: var(--bg-primary);
color: var(--text-primary);
border: 1px solid var(--border-light);
box-shadow: 0 2px 4px var(--shadow-sm);
&:hover {
box-shadow: 0 4px 8px var(--shadow-md);
}
}
.button {
background: var(--primary);
color: var(--text-inverse);
&:hover {
background: var(--primary-hover);
}
}JavaScript Toggle
// theme-toggle.js
class ThemeToggle {
constructor() {
this.theme = this.getTheme()
this.applyTheme(this.theme)
}
getTheme() {
// 1. Check localStorage
const stored = localStorage.getItem('theme')
if (stored) return stored
// 2. Check system preference
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark'
}
return 'light'
}
applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme)
localStorage.setItem('theme', theme)
this.theme = theme
}
toggle() {
const newTheme = this.theme === 'light' ? 'dark' : 'light'
this.applyTheme(newTheme)
}
}
// Usage
const themeToggle = new ThemeToggle()
document.getElementById('theme-toggle')?.addEventListener('click', () => {
themeToggle.toggle()
})
Transition Between Themes
// Smooth transitions
* {
transition-property: background-color, border-color, color, fill, stroke;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
}
// Disable transitions on page load
.no-transition * {
transition: none !important;
}
// Remove no-transition class after load
window.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
document.body.classList.remove('no-transition')
}, 100)
})
Theme Toggle Button
.theme-toggle {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 50px;
height: 50px;
border-radius: 50%;
background: var(--primary);
border: none;
cursor: pointer;
box-shadow: 0 4px 8px var(--shadow-md);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.5rem;
transition: all 0.3s ease;
&:hover {
transform: scale(1.1);
box-shadow: 0 6px 12px var(--shadow-lg);
}
// Icons
.icon-sun {
display: none;
}
.icon-moon {
display: block;
}
[data-theme="dark"] & {
.icon-sun {
display: block;
}
.icon-moon {
display: none;
}
}
}
📝 Quiz
Welche Methode ist am flexibelsten für Dark Mode?
Tipps & Tricks
System Preference Detection
// Listen to system preference changes
window.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
themeToggle.applyTheme(e.matches ? 'dark' : 'light')
}
})
Theme-Aware Images
.logo {
content: url('/logo-light.svg');
[data-theme="dark"] & {
content: url('/logo-dark.svg');
}
}
Syntax Highlighting Themes
.code-block {
// Light Theme
background: #f6f8fa;
color: #24292e;
[data-theme="dark"] & {
background: #1e1e1e;
color: #d4d4d4;
}
}
Häufige Fehler
Fehler 1: Vergessene Transitions
❌ PROBLEM:
// Harter Wechsel zwischen Themes
.card {
background: var(--bg-primary);
}
✅ LÖSUNG:
.card {
background: var(--bg-primary);
transition: background-color 200ms ease;
}
Fehler 2: Fehlende Fallbacks
❌ PROBLEM:
color: var(--text-primary);
// Keine Fallback wenn Variable fehlt
✅ LÖSUNG:
color: var(--text-primary, #000000);
Fehler 3: Flash of Unstyled Content
❌ PROBLEM:
// Theme wird nach Page Load gesetzt
window.addEventListener('load', () => {
applyTheme()
})
✅ LÖSUNG:
<script>
// Inline im <head> - vor dem Rendering
const theme = localStorage.getItem('theme') || 'light'
document.documentElement.setAttribute('data-theme', theme)
</script>
Zusammenfassung
Du hast gelernt:
- ✅ CSS Custom Properties für Themes
- ✅ prefers-color-scheme Media Query
- ✅ SCSS Maps für Theme-Management
- ✅ JavaScript Theme Toggle
- ✅ Smooth Transitions
- ✅ System Preference Detection
Key Takeaways:
- CSS Variables > separate Stylesheets
- prefers-color-scheme für Auto-Detection
- localStorage für User Preference
- Transitions für smooth Wechsel
- Inline Script gegen FOUC
Viel Erfolg mit Dark Mode! 🌙
Gut gemacht! 🎉
Du hast "SCSS Dark Mode - Theme Switching" abgeschlossen
Artikel bewerten
Bitte einloggen um zu bewerten
Das könnte dich auch interessieren
SCSS Animations - CSS Animations & Transitions
Meistere CSS Animations mit SCSS. Keyframes, Transitions, Transform und Animation Libraries für moderne Web-Effekte.
SCSS Best Practices - Professioneller Workflow
Lerne die wichtigsten Best Practices für wartbaren, performanten SCSS Code. Do's and Don'ts für Production.
SCSS Control Directives - Logik im Stylesheet
Lerne @if, @for, @each und @while für dynamische Styles und Design Systems.