Most dark mode extensions intercept every page load with a content script that injects CSS. Some use JavaScript-based theme detection, some use prefers-color-scheme media queries, some use their own inversion filters.
I wanted to understand why dark mode on the web is still such a mess, so I built NightOwl — a Firefox extension that applies dark mode without mutation observers and without touching pages it shouldn't.
The problem with most dark mode approaches
CSS inversion (filter: invert(1) hue-rotate(180deg)) is fast but breaks images, videos, and color-coded content. Media turns into negatives.
JavaScript-based theming can be more precise but adds latency to every page load. You see a white flash before the dark style applies.
Browser-level dark mode (about:config > layout.css.prefers-color-scheme.content-override) is the cleanest solution but only works for pages that actually support prefers-color-scheme. Most legacy sites still don't.
How NightOwl works
NightOwl applies dark mode selectively:
- System preference sync — if your OS is in dark mode, NightOwl defaults to dark
- Per-site memory — disable it on specific sites, the preference is remembered
- Instant toggle — the toolbar button switches mode without a page reload
- AMO-compatible manifest — uses only necessary permissions, no broad host access required
{ "permissions": ["storage"], "optional_permissions": ["<all_urls>"] } The extension uses browser.storage.local for per-site preferences and window.matchMedia("(prefers-color-scheme: dark)") to read system intent.
Why I stopped trying to fix sites that resist dark mode
Some sites actively fight dark mode — they override prefers-color-scheme with inline styles, use JavaScript to force light mode, or use CSS specificity tricks. Fighting them adds complexity and breaks their carefully designed UIs.
The right call: let the user decide per site. NightOwl's per-domain memory means you can enable dark mode globally and whitelist the sites that look wrong. The 10% of sites that fight it aren't worth breaking the 90% that work.
What I learned building a dark mode extension
The hardest part isn't the CSS. It's the edge cases: PDFs, iframes from different origins, canvas elements, SVGs with embedded colors. I scoped the first version to handle the common case well rather than try to handle every edge case poorly.
MV3 makes some things cleaner. Firefox's Manifest V3 migration has gotten clearer. Service workers are the right model for persistent background state, even if the initial migration from MV2 background pages was painful.
Dark mode preference is binary but experience isn't. People who want dark mode actually want "less eye strain at night" — which also means they want to be able to watch a YouTube video without inverting the colors. Per-site control is the right UX.
Install it
NightOwl Dark Mode on Firefox Add-ons
It's small, it's free, and it doesn't collect any data. If you're a Firefox user who lives in dark mode, give it a try.
Building Firefox extensions means shipping to real users through AMO review. If you've gone through the AMO review process and have thoughts on it, I'd like to hear them.

