close

DEV Community

Alexander
Alexander

Posted on

Stop using hex codes in your CSS

The dark mode disaster

I was reviewing a pull request for a dark mode toggle last Wednesday. The developer had written a massive CSS file. It was just hundreds of lines overriding hex codes. Things like background-color: #121212 and color: #FFFFFF were everywhere. It honestly hurt my eyes to read.

Hardcoded hex codes are a trap. We all start there. You click a button in Figma. You copy the hex code. You paste it into your CSS. It feels fast. But it creates technical debt instantly.

Let me explain why this habit ruins codebases.

Theming becomes a nightmare

If you hardcode #0052CC for your primary buttons, you create a rigid system. What happens when you need a dark theme? You have to write a media query. Then you manually map that exact hex to a new one. Now multiply that by fifty different components.

/* Please stop doing this */
.button {
  background-color: #0052CC;
  color: #FFFFFF;
}

@media (prefers-color-scheme: dark) {
  .button {
    background-color: #4C9AFF;
    color: #121212;
  }
}
Enter fullscreen mode Exit fullscreen mode

This approach scales terribly. You end up with media queries scattered across dozens of files. If the design team decides to tweak the dark mode blue, you have to hunt down every instance of #4C9AFF. It is a massive waste of time.

Opacity adjustments are terrible

Say you need a hover state. The designer wants a background with 10% opacity of that primary colour. You have two bad choices with hex codes.

You either calculate an obscure eight-digit hex code like #0052CC1A. Good luck reading that and knowing what it means. Or you convert it to RGBA manually every single time. Both options are frustrating.

Semantic CSS variables solve all of this. You define the raw values once. Then you reference them everywhere.

/* Do this instead */
:root {
  --color-brand-primary: 0 82 204;
}

.button {
  background-color: rgb(var(--color-brand-primary));
}

.button:hover {
  background-color: rgba(var(--color-brand-primary), 0.1);
}
Enter fullscreen mode Exit fullscreen mode

This is so much cleaner. You can adjust the opacity natively. You can swap the base colour in one place. The entire app updates instantly.

The naming problem

Another issue with hex codes is that they lack context. A hex code tells you what a colour looks like. It tells you absolutely nothing about how to use it.

When you see #E3F2FD in a codebase, you have to guess its purpose. Is it a background for an alert? Is it a disabled button state? Is it a table row hover effect? You do not know.

Semantic tokens fix this entirely. A variable named var(--surface-info-background) tells a clear story. Any developer can look at that and know exactly where it belongs. It removes the guesswork from building user interfaces.

The counter argument

I hear the same complaint every time I bring this up. People tell me hex codes are just easier. They say their project is too small for a full token system. They argue that copying from Figma is the fastest workflow.

And sure, if you are building a weekend side project, go wild. Paste those hex codes. But if you work on a team, you are just pushing the pain onto someone else down the line. A small project today is a legacy codebase tomorrow.

Automating the boring parts

The real issue is the handoff. Designers work in hex codes because that is how design tools display colour by default. Developers need semantic variables. You have to bridge that gap with automation.

I actually built Design System Sync to fix this exact workflow. It is a Figma plugin that takes your Figma variables and automatically turns them into semantic CSS variables. It opens a PR directly to your GitHub or Bitbucket repository. No more copying and pasting hex codes. You get proper W3C design tokens straight into your codebase. It even handles multi-mode exports for light and dark themes out of the box.

It takes an hour to set up a proper semantic colour system. It takes weeks to untangle a massive app full of hardcoded hex values. Stop pasting them into your code.

Are you still copying hex codes manually, or have you finally moved to semantic tokens?

Top comments (0)