October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
CSS

How to Implement Dark Mode on a Web Page (CSS, JavaScript, and Testing)

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The most maintainable dark mode starts with CSS: define semantic color tokens, set color-scheme: light dark, and switch those tokens inside @media (prefers-color-scheme: dark). Add JavaScript only when visitors need a site-level light/dark choice that is remembered across visits. This keeps the page usable when scripts fail while still allowing an explicit override.

The implementation below covers the CSS-only pattern, an accessible three-state control, browser-rendered controls, embedded content, compatibility, testing, and common failure modes.

1. Build a CSS-first theme

prefers-color-scheme exposes the light or dark preference reported by the user agent or operating system. It does not design a palette for you; your stylesheet must define the colors. The media feature is documented by MDN.

Use semantic custom properties instead of scattering literal colors through component rules. Then every component consumes the same tokens.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Sale
Philips 24 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 241V8LB
  • CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
  • WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
  • A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
:root {
  color-scheme: light dark;
  --page-bg: #ffffff;
  --page-fg: #202124;
  --surface: #f3f4f6;
  --border: #d7dbe0;
  --accent: #1558a6;
  --muted: #5f6368;
}

@media (prefers-color-scheme: dark) {
  :root {
    --page-bg: #17191c;
    --page-fg: #f2f3f5;
    --surface: #24272b;
    --border: #454a51;
    --accent: #9fc5ff;
    --muted: #c0c5cc;
  }
}

html, body {
  background: var(--page-bg);
  color: var(--page-fg);
}

body {
  margin: 0;
  font: 1rem/1.5 system-ui, sans-serif;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
}

a { color: var(--accent); }
.small-print { color: var(--muted); }

The values above are illustrative, not an accessibility audit. Check the actual text sizes, fonts, hover states, disabled states, focus indicators, and content in both palettes. “Dark” can be charcoal, navy, or another low-luminance surface; it does not require pure black and white.

Tell the browser about supported schemes

The color-scheme property allows browser-controlled UI such as form controls and scrollbars to use a compatible treatment. The CSS Color Adjustment specification explains the mechanism; see MDN and the W3C specification.

Also place this declaration early in the document head, before stylesheet links when possible:

<meta name="color-scheme" content="light dark">

That gives the user agent an early hint and can reduce a flash of incorrectly styled native controls while CSS is loading.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Add a manual light/dark choice only when you need one

A CSS-only site follows the device setting and needs no script. If your product offers a theme control, keep the system preference as the default, save only an explicit light or dark choice, and apply that choice before the page paints.

Rank #2
Philips 22 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 221V8LB
  • CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
  • SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors

Head script to prevent a wrong-theme flash

Put this small script before your main stylesheet. It sets a data attribute only when a visitor has previously selected a mode; otherwise the CSS media query remains in charge.

<script>
(() => {
  const saved = localStorage.getItem('theme');
  if (saved === 'light' || saved === 'dark') {
    document.documentElement.dataset.theme = saved;
  }
})();
</script>

Override tokens and browser UI

:root[data-theme="light"] {
  color-scheme: light;
  --page-bg: #ffffff;
  --page-fg: #202124;
  --surface: #f3f4f6;
  --border: #d7dbe0;
  --accent: #1558a6;
  --muted: #5f6368;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --page-bg: #17191c;
  --page-fg: #f2f3f5;
  --surface: #24272b;
  --border: #454a51;
  --accent: #9fc5ff;
  --muted: #c0c5cc;
}

/* Used only when no data-theme override exists. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --page-bg: #17191c;
    --page-fg: #f2f3f5;
    --surface: #24272b;
    --border: #454a51;
    --accent: #9fc5ff;
    --muted: #c0c5cc;
  }
}

Provide a clear three-state control

A select with “System”, “Light”, and “Dark” makes the meaning explicit. The system option removes the saved override rather than storing a third invented color value.

<label for="theme-choice">Theme</label>
<select id="theme-choice">
  <option value="system">System</option>
  <option value="light">Light</option>
  <option value="dark">Dark</option>
</select>

<script>
const root = document.documentElement;
const choice = document.getElementById('theme-choice');
const media = window.matchMedia('(prefers-color-scheme: dark)');

function readSaved() {
  return localStorage.getItem('theme');
}

function syncChoice() {
  choice.value = readSaved() || 'system';
}

choice.addEventListener('change', () => {
  if (choice.value === 'system') {
    localStorage.removeItem('theme');
    delete root.dataset.theme;
  } else {
    localStorage.setItem('theme', choice.value);
    root.dataset.theme = choice.value;
  }
});

media.addEventListener?.('change', () => {
  if (!readSaved()) {
    delete root.dataset.theme;
  }
});

syncChoice();
</script>

The listener matters when a visitor leaves the setting at System and changes the operating-system preference while your page is open. The CSS still provides the fallback if JavaScript or storage is unavailable. Treat storage failures as non-fatal: private browsing policies, disabled storage, or a restrictive security policy can prevent persistence.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Decide between the main implementation approaches

Approach Strength Trade-off Best fit
CSS prefers-color-scheme Minimal code and automatic system preference support No site-specific override Content sites that should follow the device
CSS tokens plus JavaScript override Visitors can choose and persist a mode Requires early state handling and preference-change behavior Applications with a visible theme setting
light-dark() with a media-query fallback Compact paired color declarations Requires support checking and a fallback for older browsers Projects targeting current browsers

light-dark() can express two alternatives in one declaration when the active color scheme is set:

:root {
  color-scheme: light dark;
  --page-bg: light-dark(#ffffff, #17191c);
  --page-fg: light-dark(#202124, #f2f3f5);
}

body {
  background: var(--page-bg);
  color: var(--page-fg);
}

Retain the media-query version when older browser support is part of your requirements. Chrome’s modern web guidance lists light-dark() as newly available from May 13, 2024 and recommends a prefers-color-scheme fallback; verify the versions you actually support in the guidance.

Rank #3
Sale
Dell 24 Monitor - SE2426H - 23.8-inch FHD (1920x1080) 144Hz 1ms Display, in-Plane Switching (IPS) Technology, AMD FreeSync™, TÜV 3-Star 2X HDMI, Tilt
  • Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
  • Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
  • Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
  • In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
  • Ultra-thin bezels: Maximize your viewing experience with thin bezels.

4. Audit every surface, state, and asset

Changing the page background and body text is only the beginning. Walk through a representative page in both modes and inspect:

  • navigation, cards, dialogs, tables, code blocks, and tooltips;
  • links, visited links, hover, active, disabled, and keyboard-focus states;
  • inputs, selects, checkboxes, date pickers, validation messages, and placeholder text;
  • icons, logos, charts, photos, SVG illustrations, and transparent PNGs;
  • sticky headers, shadows, borders, separators, and loading or error states;
  • third-party widgets, cookie notices, chat panels, and embedded documents.

Specify foreground and background together rather than relying on system colors mixed with author colors. The W3C CSS Color Adjustment specification cautions that a scheme label does not guarantee a particular contrast level. The WAI C23 technique is an example of allowing user-agent preferences; it is not a substitute for checking your own design.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Images and logos

Do not apply a blanket filter: invert() to an entire page. It can damage photographs, brand colors, and semantic icons. Supply a dark-appropriate asset, use an SVG whose fills reference theme tokens, or place a light logo on a deliberate surface. If an image must remain unchanged, document that choice and check its surrounding border and caption in dark mode.

Embedded SVG and iframe content

MDN documents that embedded SVG and iframe content can respond to the parent color scheme in applicable contexts. Browser behavior still differs. Chrome’s guidance notes that Safari resolves the preference to the system setting inside an iframe rather than the embedding context. If your application controls both documents, pass the selected theme explicitly (for example, through a URL or messaging protocol) and test the browsers relevant to your users.

5. Compatibility, loading, and performance

MDN describes prefers-color-scheme as widely available across many devices and browser versions since January 2020, while noting that details vary. Chrome’s guidance lists color-scheme as widely available since February 3, 2022. These are documentation dates, not guarantees for every browser version; use your project’s support matrix and test devices.

Rank #4
Samsung 27" Essential S3 (S36GD) Series FHD 1800R Curved Computer Monitor
  • CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
  • SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
  • MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
  • KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
  • INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
  • Keep the first-paint script tiny and synchronous in the head; defer the control wiring until the document is available.
  • Use one token layer instead of duplicating complete component styles for each mode.
  • Avoid loading a second image or font set solely for dark mode unless the visual benefit justifies the request.
  • When server-rendering, do not assume the server knows a visitor’s OS preference. Render the neutral token set and let CSS select the mode, or use a previously consented preference cookie if your architecture already has one.
  • Test with JavaScript disabled and with storage blocked. The page should still follow the system preference and remain legible.

6. Test the result systematically

  1. Set the operating system or browser to Light, reload, and inspect the first paint.
  2. Repeat in Dark and compare every page template, not just the home page.
  3. Select Light and Dark in your control, reload, and confirm the saved choice wins over the system setting.
  4. Select System, change the OS preference while the page is open, and verify the page updates.
  5. Tab through the interface in both modes; focus rings must remain visible.
  6. Open forms, menus, dialogs, print previews, and embedded content. Check hover, validation, and disabled states.
  7. Capture representative URLs in both modes for visual regression review. A screenshot is evidence of the rendered result, not proof of accessibility; pair it with keyboard and contrast checks.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

7. Troubleshoot common failures

The page never changes when the OS changes

Check that the rule is exactly @media (prefers-color-scheme: dark), that no later selector overrides the tokens, and that a stale data-theme="light" attribute is not forcing an override. Remove the saved value or choose System.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Native controls stay bright

Set color-scheme: light dark on the root and include the early meta tag. For a manual override, set color-scheme: light or dark in the corresponding root selector.

A flash appears on reload

Move the storage-reading script before the stylesheet, keep it free of asynchronous work, and make sure your CSS defines a usable system fallback. Do not wait for a framework mount to set the theme.

The toggle works but resets every visit

Confirm that the key name is identical for reads and writes, that storage is available, and that code is not clearing storage during initialization. If storage is intentionally unavailable, present System as the reliable fallback.

Some text or widgets remain unreadable

Search for hard-coded colors, inline styles, SVG fills, canvas drawings, and third-party components. Replace literals with tokens where you own the markup; configure or isolate components you do not control.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Sale
Sceptre New 22-Inch Gaming Monitor, FHD 1080p, Up to 144Hz, HDMI, DisplayPort, Built-in Speakers, Machine Black (E225W-FW144 Series, 2026)
  • 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
  • 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
  • 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.

An iframe disagrees with the parent

Test Safari separately, because its iframe preference resolution can follow the system rather than the embedding document. If both sides are yours, send the chosen theme to the iframe and apply it there.

Or skip the browser setup

To review how your finished page renders without writing a local capture script, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one request. It accepts the page as a visitor, removes cookie-consent banners, newsletter popups, and chat widgets before capture, and bills only clean shots: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing result in X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

Use the same URL in your light and dark test cases (for a manual override, set the page state before capture or use ScreenshotNeo’s custom JavaScript option):

cURL — see the ScreenshotNeo API documentation for all parameters.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://freedom251.com -o shot.webp

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://freedom251.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://freedom251.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

You can also set a viewport or device preset, wait for a selector, load lazy images on a full-page capture, hide selectors, block requests, provide headers or cookies, run custom CSS or JavaScript, resize the output, choose a cache TTL, or submit asynchronous jobs and signed webhooks. Every feature is included on every plan. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to start.

8. A practical release checklist

  • Tokens define page, surface, text, border, accent, and muted colors.
  • The root declares supported schemes and the head includes the color-scheme meta tag.
  • System preference works with JavaScript disabled.
  • Manual choices are explicit, persisted, and reversible through System.
  • First paint does not flash the wrong saved mode.
  • Focus, form, validation, disabled, hover, and error states are readable in both palettes.
  • Images, SVGs, iframes, and third-party widgets have a deliberate treatment.
  • Target browsers, Safari iframe behavior, storage failures, and representative pages have been tested.

Frequently Asked Questions

Should dark mode change the printed page?

Usually no. Define a separate @media print policy so paper output uses an ink-friendly background and text treatment instead of inheriting a screen-only dark surface.

Can a browser extension or user stylesheet override my theme?

Yes. Author CSS is not the final authority. Keep content meaningful without depending on a single exact color, and avoid conveying status by color alone.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.