Light & Dark Modes
Semanticus CSS supports light and dark modes out of the box, automatically adapting to your users' system preferences or allowing explicit control via the data-theme attribute.
Automatic System Detection
By default, Semanticus CSS respects the user's OS color scheme preference using the prefers-color-scheme media query:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@semanticus/semanticus-css@3.1.3/dist/semanticus.css">
</head>
<body>
<!-- Content automatically adapts to system theme -->
</body>
</html>The <meta name="color-scheme" content="light dark"> tag is essential—it tells the browser your site supports both themes and enables native UI elements (scrollbars, form controls) to adapt automatically.
Explicit Theme Control
Override the automatic detection by setting the data-theme attribute on the <html> or <body> element:
Force Light Mode
<html lang="en" data-theme="light">Force Dark Mode
<html lang="en" data-theme="dark">Dynamic Theme Switching
Add a theme toggle button to let users switch between light and dark modes:
<button id="theme-toggle">Toggle Theme</button>
<script>
const toggle = document.getElementById('theme-toggle');
const html = document.documentElement;
toggle.addEventListener('click', () => {
const current = html.getAttribute('data-theme');
html.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
});
</script>Element-Level Theme Contrast
Apply data-theme="contrast" to any element to flip it to the opposite color scheme from the rest of the page. When the page is in light mode, the element renders in dark mode, and vice versa. This is useful for sidebars, hero sections, or any UI area you want to visually separate from the main content.
<body>
<!-- Page in light mode -->
<main>
<h1>Main Content</h1>
<p>This area follows the light theme.</p>
</main>
<!-- Sidebar automatically flips to dark mode -->
<aside data-theme="contrast">
<nav>
<ul>
<li><a href="#about">About</a></li>
<li><a href="#getting-started">Getting Started</a></li>
</ul>
</nav>
</aside>
</body>This works at any nesting depth — you can place a data-theme="contrast" element inside another data-theme="contrast" container to flip back to the original theme.
How It Works
Semanticus CSS uses CSS custom properties and container style queries to manage themes:
- Light theme (default) — Applied via
[data-theme="light"]or:root:not([data-theme="dark"]) - Dark theme (system preference) — Applied via
@media (prefers-color-scheme: dark)when nodata-themeis set - Dark theme (explicit) — Applied via
[data-theme="dark"]regardless of OS preference - Element-level contrast — Applied via
[data-theme="contrast"]using@container style()queries to invert the current theme
All semantic color variables (--primary-color, --background-color, --color, etc.) are redefined in each theme to ensure optimal contrast and readability.