Successfully implemented a comprehensive light/dark theme system using modern CSS light-dark() function with the following features:
- ✅ Light and dark mode support using CSS
light-dark()function - ✅ Dual-theme syntax highlighting with Shiki
- ✅ User preference detection (system preference via
color-scheme) - ✅ Theme toggle button in top-right corner
- ✅ Persistent theme selection (localStorage)
- ✅ Smooth transitions between themes
- ✅ No flash of wrong theme on page load
- ✅ Elephant bone color for light mode background
- ✅ Pure white text in dark mode
Location: /src/components/theme-toggle/ThemeToggle.astro
- Absolute positioned button in top-right corner (top: 2rem, right: 2rem)
- Animated sun/moon icons with smooth transitions
- Matches application design with theme colors
- Z-index: 200 to stay on top
- Uses
color-schemeproperty for theme switching
Location: /src/styles/global.css
Using the modern light-dark() CSS function for clean, efficient theming:
/* Elephant bone color for light mode */
--color-elephant-bone: hsl(48 20% 96%);
/* Theme colors using light-dark() */
--color-bg-primary: light-dark(var(--color-elephant-bone), hsl(0 0% 10%));
--color-bg-secondary: light-dark(hsl(48 20% 96% / 0.85), hsl(0 0% 10% / 0.85));
--color-text-primary: light-dark(hsl(0 0% 0%), hsl(0 0% 100%));
--color-gray-700: light-dark(hsl(0 0% 40%), hsl(0 0% 70%));
--color-gray-900: light-dark(hsl(0 0% 10%), hsl(0 0% 90%));
--color-code-bg: light-dark(hsl(279deg 92% 90%), hsl(283 91% 20%));
/* Direct usage in CSS */
h1, h2, h3, h4, h5, h6 {
color: light-dark(black, white);
}
p {
color: light-dark(black, white);
}Location: /src/utils/shiki-helper.ts
Created helper function for dual-theme syntax highlighting:
- Light theme:
github-light - Dark theme:
github-dark - Uses Shiki's built-in dual theme support
- Updated all slide files to use the helper
Files Updated:
- AdvancedSyntax.astro
- BasicSyntax.astro
- BestPractices.astro
- ScrollableState.astro
- ScrollableStateAdvanced.astro
- SnappedState.astro
- SnappedStateAdvanced.astro
- StuckState.astro
- StuckStateAdvanced.astro
Location: /astro.config.mjs
Updated MDX integration to support dual themes:
shikiConfig: {
themes: {
light: "github-light",
dark: "github-dark",
},
defaultColor: false,
}Location: /src/pages/index.astro
Added inline script in <head> to prevent flash of wrong theme:
- Runs before page renders
- Reads from localStorage or system preference
- Sets
color-schemeproperty on<html>element
The entire theme system works through the CSS color-scheme property:
<html>element hascolor-scheme: light darkdeclared- JavaScript toggles between
lightanddarkviadocument.documentElement.style.colorScheme - The
light-dark()CSS function automatically responds to the color-scheme
Slide Component (/src/components/slide/Slide.astro):
- Background uses
var(--color-bg-secondary)withlight-dark()function - Smooth color transitions
Footer Component (/src/components/footer/Footer.astro):
- Background uses
light-dark(black, hsl(0 0% 5%)) - Smooth transitions
Body Element (/src/pages/index.astro):
- Background uses
var(--color-bg-primary) - Sets
color-scheme: light dark
Theme Toggle (/src/components/theme-toggle/ThemeToggle.astro):
- Icons and background use
light-dark()function - Icons switch based on
prefers-color-schememedia query
- Default Behavior: Matches user's system color scheme preference
- Toggle: Click the button in top-right corner to switch themes
- Persistence: Theme choice saved to localStorage
- No Flash: Theme applied before page renders via inline script
- Smooth Transitions: All color changes animate smoothly (300ms)
- Light Mode: Elephant bone background (#F7F5F0) with black text
- Dark Mode: Dark gray background with pure white text
- Modern CSS
light-dark()Function: Clean, efficient theme switching - CSS
color-schemeProperty: Native browser theme support - Tailwind CSS 4: Using modern
@themedirective - Astro 5: Server-side rendering with client-side hydration
- Shiki 3: Dual-theme syntax highlighting
- localStorage: Theme persistence
- CSS Custom Properties: Dynamic theming with
light-dark()
Works in all modern browsers that support:
- CSS
light-dark()function (Chrome 123+, Safari 17.5+, Firefox 120+) - CSS
color-schemeproperty - CSS custom properties
prefers-color-schememedia query- localStorage
- ES6+ JavaScript
Fallback: Browsers without light-dark() support will default to light mode values.
- Cleaner CSS: No need for duplicate styles with
.darkclasses - Better Performance: Browser-native theme switching
- More Maintainable: Single source of truth in
light-dark()function - Standards-Based: Uses official CSS specifications
- Automatic:
light-dark()automatically responds tocolor-schemechanges - Elegant: Elephant bone (#F7F5F0) in light mode, pure white text in dark mode
Potential improvements:
- Add transition preferences for accessibility (
prefers-reduced-motion) - Support for high contrast modes
- Additional theme options (e.g., auto-schedule based on time)
- Theme preference sync across tabs using BroadcastChannel API