Why Your Website Needs Dark Mode (And How to Add It)
Dark mode isn’t just trendy-it’s essential. Here’s why and how to implement it properly.
Why Your Website Needs Dark Mode (And How I Actually Built Mine)
I’m going to tell you something embarrassing: I spent more time on the dark mode toggle for this site than I did on the entire contact page. And I’d do it again.
If you’re reading this on 211j.com right now, look up at the nav. See that little sun/moon toggle? That’s not a plugin. That’s not a library. That’s me, hand-rolling CSS custom properties at 2 AM because I’m the kind of person who reverse-engineers things instead of installing a package like a normal human being.
Why I Built It
The honest answer? Because I wanted to. I’ve got textbook, if undiagnosed, ADHD, and I’m FOMO-driven when it comes to technology, so when dark mode became a thing that operating systems shipped natively, I couldn’t not build it. But there’s a practical reason too: I stare at screens all day. I build WordPress sites. I write code. I debug at night. My eyes are tired. If I’m going to ask other people to look at my site, the least I can do is not assault their retinas.
Plus, I do ADA compliance work. It’s one of my four core services. Building a site that respects user preferences isn’t just nice - it’s part of the job. If I’m telling clients their sites need to be accessible, mine better be too.
How It Actually Works
The whole system runs on a data-theme attribute on the <html> element. Light mode is the default. When you click the toggle, JavaScript flips data-theme from "light" to "dark", and CSS custom properties handle the rest.
Here’s the basic idea in the CSS:
:root {
--bg: #ffffff;
--text: #111111;
--accent: #008080;
}
[data-theme="dark"] {
--bg: #111111;
--text: #f5f5f5;
--accent: #00b3b3;
}
Every color in the theme references these variables. Background, text, borders, links, buttons - all of it. When the attribute flips, the entire site repaints with the new palette. No class toggling on fifty different elements. No separate stylesheet. Just swap the variables at the root and let CSS do what CSS does.
I built this site with Tailwind CSS, Vite, and vanilla JavaScript. No jQuery. No React. Just plain JS that does exactly what I need and nothing else. The toggle button stores your preference in localStorage so when you come back tomorrow, you get the same mode you left with.
The FOUC Problem (And Why It Matters)
Here’s where most dark mode tutorials fall apart. They tell you to check localStorage in your JavaScript file, which loads after the page renders. So what happens? The page flashes white for a split second before going dark. It’s called FOUC - Flash of Unstyled Content - and it looks terrible. It’s like your site is flinching.
The fix is stupid simple but almost nobody mentions it. I put a tiny inline script in the <head>, before any stylesheets load:
<script>
(function() {
document.documentElement.classList.remove('no-js');
var theme = localStorage.getItem('theme');
if (theme === 'dark') {
document.documentElement.setAttribute('data-theme', 'dark');
}
})();
</script>
This runs synchronously before the browser paints anything. By the time CSS kicks in, the data-theme attribute is already set. No flash. No flicker. The user sees exactly what they expect on the very first frame.
I know inline scripts make some developers twitch, but this is one of those cases where it’s the right call. It’s five lines. It runs once. And it prevents a genuinely bad user experience.
System Preference Detection
The other thing I built in: if you’ve never visited before and haven’t set a preference, the site checks your OS setting with prefers-color-scheme. If your Mac or phone is in dark mode, my site follows suit. And it listens for changes - if you flip your system theme while my site is open, it updates in real time.
But here’s the key detail: your explicit choice always wins. If you click the toggle, that preference is saved in localStorage and the system detection backs off. I think that’s how it should work. Respect the system default, but respect the user’s active choice even more.
Screen Reader Announcements
This is the part that most people skip entirely, and it drives me nuts because it takes about four lines of code. When you click the toggle, a visually hidden aria-live region announces “Dark mode enabled” or “Light mode enabled” to screen readers. The toggle button itself has aria-pressed that updates with the state, and the aria-label changes to tell you what clicking it will do next.
It’s not hard. It’s not expensive. It’s just something you have to actually think about, which apparently disqualifies it from 90% of dark mode implementations on the internet.
Comfort Mode: The Other Toggle
While I was building the dark mode toggle, I figured - why stop there? I added a second toggle for what I call “comfort mode.” It bumps up the base font size and line height across the entire site. Same mechanism: a data-display attribute on the HTML element, CSS custom properties, localStorage persistence, FOUC prevention, screen reader announcements. The whole deal.
Some people need bigger text. Some people prefer it. Either way, it’s a button click, not a browser zoom that breaks the layout. And the two toggles sit right next to each other in the nav - Aa/AA for display, sun/moon for theme. Clean, obvious, no explanation needed.
Why Not Just Use a Plugin?
Because I’d have to read someone else’s code anyway. That’s how my brain works. I can’t use something I don’t understand. When I was learning WordPress, I didn’t just install themes - I read the source line by line until I understood the hook system. When I built my first site, it was in GoDaddy’s terrible little modal editor with no line numbers. I’ve always been the kind of developer who needs to know what’s happening under the hood.
A dark mode plugin would bring in dependencies I don’t need, styles that might conflict with Tailwind, and JavaScript that does things I didn’t ask for. My implementation is maybe 40 lines of JS and a handful of CSS variables. I know exactly what it does because I wrote every line. When something breaks, I know where to look.
Should You Build Dark Mode?
If you’re a developer: yes, build it yourself. It’s not hard, and you’ll learn things about CSS custom properties and accessibility that make you better at your job. If you’re not a developer: find a good plugin or hire someone, but make sure they handle FOUC prevention and screen reader support. If those two things aren’t in the implementation, it’s half-baked.
Dark mode isn’t a gimmick anymore. It’s a user expectation. People toggle their phones to dark at night, and they notice when a website blinds them. Building it well - with persistence, system detection, no flash, and proper accessibility - takes maybe a day of work. That’s a pretty good investment for something your visitors will use every single time they come back.