Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      15 Essential Skills to Look for When Hiring Node.js Developers for Enterprise Projects (2025-2026)

      August 4, 2025

      African training program creates developers with cloud-native skills

      August 4, 2025

      React.js for SaaS Platforms: How Top Development Teams Help Startups Launch Faster

      August 3, 2025

      Upwork Freelancers vs Dedicated React.js Teams: What’s Better for Your Project in 2025?

      August 1, 2025

      LastPass can now warn or block logins to shadow SaaS apps – here’s how

      August 4, 2025

      Get up to a year of Adobe Creative Cloud access for 40% off

      August 4, 2025

      Got 6 hours? This free AI training from Google and Goodwill can boost your resume today

      August 4, 2025

      Why I recommend this budget phone with a paper-like screen over ‘minimalist’ devices

      August 4, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Using GitHub Copilot in VS Code

      August 4, 2025
      Recent

      Using GitHub Copilot in VS Code

      August 4, 2025

      Optimizely Mission Control – Part I

      August 4, 2025

      Highlights from the 2025 Formula SAE and Formula Student Season

      August 4, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Top 20 kubectl Commands Every Kubernetes Beginner Must Know

      August 4, 2025
      Recent

      Top 20 kubectl Commands Every Kubernetes Beginner Must Know

      August 4, 2025

      Microsoft’s record stock run collides with Nadella’s admission that 15,000 layoffs still ‘hurt’

      August 4, 2025

      Microsoft and Adobe Power Up Fantasy Premier League Fans with AI – Here’s How

      August 4, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»Thinking Deeply About Theming and Color Naming

    Thinking Deeply About Theming and Color Naming

    August 4, 2025

    As a front-end developer, I’ve been pretty curious about how other people code up their websites. So I tend to poke my head into design systems whenever I find one.

    Then, late last year, a conversation with Geoff Graham set me off thinking even deeper about theming websites. (If you don’t know that dude, he’s the chief editor of this site, so that guy’s a pretty big deal, too.)

    So I’ve been watching, pondering, and exploring:

    • How can we create better themes?
    • How can we allow increased flexibility in theming?
    • How can we allow more colors to be used so that sites can be more alive and dimensional instead of being so flat all the time?

    Today, I want to discuss a couple of patterns that the community is using, and how I propose we can improve, so we achieve both flexibility and beauty.

    Hope you’re ready to go on a wild ride with me!

    Color Palettes

    Let’s begin from the beginning. After all, how can you discuss theming without including colors into the site?

    I think this problem is pretty much solved by now. Everyone has adopted systems that allows for various hues — along with multiple tints and shades — that can give some life to the design.

    We don’t need to go very far to see this trend happening. For example, Tailwind CSS includes a ton of colors and their respective tones.

    A color palette matrix in rows of red, orange, amber, yellow, and lime. Each column is a square box with a color corresponding to its row, getting increasingly darker from left to right.

    Open Props by Adam Argyle provides even more tones, up to 13 per color.

    A larger color palette with 19 rows of color, each with 13 columns showing the color getting darker from left to right.

    And Pico CSS ups the ante by introducing 19 different tones per color.

    Two color palettes, one for red and one for pink, each with a grid of squares showing the variations going from light to dark.

    Er… this is not a race, so the number of tones doesn’t really matter. What’s important is you get sufficient color tones to create subtle effects for various parts of the design.

    Designing Your Own Palette

    Color palettes provided by these libraries and frameworks can be good starting points, but I’d argue that you almost never want to use them.

    Why?

    Because colors create differentiation; differentiation creates distinction; distinction creates identity.

    You probably know this is true without me telling you.

    • Sites that use Bootstrap, look like Bootstrap.
    • Sites that use Tailwind, look like Tailwind.
    • Sites that use shadcn, look like that too…

    Of course there are makers who can break the mould, use Tailwind, and make it completely not like Tailwind. But that’s because they tweak many things.

    Color is one of these things — one of the most important ones — but other important pieces include typography, spacing, the roundness of your corners… and many others. Covering those is a story for another day, and perhaps best covered by Jack McDade who teaches Radical Design.

    So, if you don’t wanna drown in the sea of sameness — looking like everyone else — creating your own color palettes is a first step forward.

    Now, you may be anxious about creating color palettes because there’s been lots of writing about the amount of work that goes into creating accessible color palettes, so that might sound like a daunting task.

    Plus, anything related to accessibility carries “Big Potential Consequences” and “Highly Shameful When Done Incorrectly,” so that can add extra pressure on you.

    Throw all those pressures away.

    Don’t be scared.

    Because if you want to create a corner of the internet that looks like you (or your company), breathes like you, acts like you, and exudes fun like you do, then gotta do what you gotta do.

    There are only two words you have to remember.

    Just two words.

    Sufficient contrast.

    And you’re set for accessibility (design-wise, at least).

    That’s it.

    Designing Color Palettes by Hand

    I tend to design color palettes by hand — in Figma — when I design my websites. This seems to be the most natural process for me. (Or maybe I’m just influenced by how Jack designs stuff 🙃).

    If you do this, there’s no need to stress about filling up tones from 50 to 950. That’s because you’ll have no idea what colors would look nice before you fit them into the design. Stressing over tones is putting the cart before the horse.

    Here’s a decent example. When I designed Splendid Labz, I omitted a ton of color tones. Here’s an example of the pink color variables for the site.

    Showing 10 CSS variables for pink-based color variations defined in oklch().
    • Notice I skipped values between 50 and 400? Well, I didn’t need ’em.
    • Notice I added 200d and 600d? Well, I kinda wanted a desaturated (or muted) variant of these colors… which… could not be captured the existing systems. So I added d for desaturated 🙃.

    You can see the results of that yourself. It’s not too shabby in my opinion — with splashes of color that perhaps bring some joy to your face when you scroll through the site.

    The Splendid Labz homepage. Black background, yellow heading, white body text. Rediscover the joy of coding.

    You get the drift, yeah? It’s not too hard. So, don’t be scared and give that a try.

    Designing Color Palettes Programmatically

    If you’re the kinda person that prefers generating colors programmatically (and of course you can hand-tweak them afterwards if you desire), here are a few generators you may fancy:

    • RampenSau
    • Perceptual Palettes
    • Accessible Palette Generator

    Of these, I highly recommend checking out @meodai‘s RampenSau because he’s really knowledgeable about the color space and does incredible work there. (Use the monochromatic feature to make this easy.)

    🎉 Just released RampenSau v1.0.0 on npm and GitHub! 🎢🐷

    After some Easter weekend coding, the color palette generation library is now stable with improved docs and APIs.

    Generate beautiful color ramps for your data viz, design work, or generative art!

    meodai.github.io/rampensau/

    [image or embed]

    — David Aerne (@meodai.bsky.social) April 21, 2025 at 3:55 PM

    Using the Color Palettes

    A thousand words later, we’re finally getting to the meat of this article. 😅

    With a seemingly unlimited amount of options given by the color palettes, it makes sense to assume that we can use them however we want — but when it comes to application, most systems seem to fall short.

    (Even short is generous. They actually seem to be severely restricted.)

    For example, DaisyUI seems to support only two tones per color…

    Showing a table of color variables named by utility, including primary, secondary, and accent. The table contains a column showing the color in a square, a column for the color name, a column for the variable, and a column for use case.

    Pico CSS, a system with one of the most options, on first glance, limits to 10 possible variants “semantic class names“.

    Showing 10 CSS variables naming color by their use, such as pico-primary-background and pico-primary-border.

    But if you look deeper, we’re still looking at about two tones per “thing”:

    • Primary (one tone)
    • Background and background hover (two tones)
    • Border and border hover (two tone)
    • Underline (is this the same as border? More on this below.)
    • And so on…

    Which brings me to one very important and very puzzling question:

    If colors are so important, why do these frameworks allow only the utilization of so few colors?

    I can’t answer this question because I’m not the creators behind those systems, but I’d guess these might be the possible causes:

    1. These system designers might not be as sensitive to colors as visual designers.
    2. Semantic class name confusion.
    3. Values were simply meant as guidelines.

    The second one a serious, and limiting, issue that we can deal with today.

    As for the first, I’m not saying I’m a great designer. I’m simply saying that, with what I know and have discovered, something seems to be amiss here.

    Anyway, let’s talk about the second point.

    Semantic Class Name Confusion

    Observing the “semantic class names” these systems use actually unveil underlying confusion about what “semantic” means to the web development community.

    Let’s go back to my remark about the --pico-primary-underline variable earlier with Pico CSS.

    But if you look deeper, we’re still looking at about two tones per “thing”

    • Primary (one tone)
    • Background and background hover (two tones)
    • Border and border hover (two tones)
    • Underline (is this the same as border? More on this below)
    • And so on…

    Isn’t that an interesting remark? (I ask this question because underline and border can use the same color to create a unifying effect).

    From what we can see here, the term “semantic” actually means two things conflated into one:

    1. An order of hierarchy (primary, secondary, tertiary, etc)
    2. The “thing” it was supposed to style

    This gets even more confusing because the order of hierarchy can now be split into two parts:

    1. A color-specific order (so primary means red, secondary means blue, and so on)
    2. A use-case specific order (so a heavy button might be primary, while a light button might be secondary)
    Two differently styled buttons side-by-side, one solid blue with white text and one transparent with a red border and text. It is unclear which one is the primary button and which is the secondary button.

    Okay. I can hear you say “naming is hard.” Yes, that’s the common complaint. But “naming is hard” because we conflate and reduce things without making distinctions.

    I propose that:

    1. We keep the hierarchy (primary, secondary, tertiary) to the color hue.
    2. We name the strength, “oomph,” or weight of the button with a verb that describes their relative weight or appearance, like outline, light, heavy, ghost, etc.
    Four rows of color families, including pink, orange, yellow, and turquoise. Each has variations for heavy, light, outline, and ghost.

    We can create the appearance variations easily with something I call The Pigment System. But perhaps that’s an article for another day.

    Anyway, by creating this separation, we can now create a wealth amount of color combinations without being restricted by a single hierarchical dimension.

    Moving on…

    The Second Problem With Semantics

    Using the same example (just for simplicity, and definitely not trying to bash Pico CSS because I think they’re doing a really good job in their own right), we see that semantics are conflated by stating its hierarchy along what its supposed to style.

    Examples are:

    • --pico-primary-background
    • --pico-primary-border

    These two properties result in a problem when designing and developing the site later. If you consider these questions, you’d see the problems too:

    First: By using --pico-primary-background…

    • Does it mean we only have one main background color?
    • What if we need other colors? Do we use --pico-secondary-background?
    • What if we need more? Do we use tertiary (3rd), quaternary (4th), quinary (5th), and senary (6th) for other colors?

    Second: What if we have variants of the same color? Do we use things like --pico-primary-background-1, 2, 3, and so on?

    Third: Now, what if I need the same color for the --pico-primary-background and the --pico-primary-border of the same component? But I’d need another color for a second one?

    This starts getting confusing and “semantics” begins to lose its meaning.

    What Semantics Actually Mean

    Consulting Etymology and the dictionary gives us clues about how to actually be semantic — and keep meaning.

    Semantic, adjective. Relating to significance or meaning," 1894, from French sémantique, applied by Michel Bréal (1883) to the psychology of language, from Greek sēmantikos
"significant," from semainein "to show by sign, signify, point out, indicate by a sign," from sēma "sign, mark, token; omen, portent; constellation; grave" (Doric sama), from PIE root *dheie- "to see, look" (source also of Sanskrit dhyati "he meditates;" see zen).
    Semantic, relating to meaning in language or logic.

    Two things we can see here:

    1. Semantics mean to indicate by a sign.
    2. It can be related to meaning or logic.

    What I’m noticing is that people generally ascribe “semantics” to words, as if only words can convey meanings and numbers cannot…

    But what if we broaden our scope and view numbers as semantic too — since we know 100 is a much lighter tint and 900 is a dark shade, isn’t that semantics showing through numbers?

    Better Semantics

    We already have a perfectly usable semantic system — using numbers — through the color palettes.

    Showing a color palette grid for the Tailwind framework.
    This is highly semantic!

    What we simply need is to adjust it such that we can use the system to easily theme anything.

    How? Simple.

    I made the argument above that the hierarchy (primary, secondary, etc.) should be used to refer to the colors.

    • Then, if you have use pink color as your main (hence primary) color…
    • You can simply set another color, say orange as your secondary color!

    (Duh? Yeah, it’s obvious in hindsight.)

    Implementing this into our code, we can do a one-to-one port between hierarchy and hues. If you do this via CSS, it can be manual and not very fun…

    .theme-pink {
      --color-primary-100: var(--color-pink-100);
      --color-primary-200: var(--color-pink-200);
      --color-primary-300: var(--color-pink-300);
      /* and so on ...*/
    
      --color-secondary-100: var(--color-orange-100);
      --color-secondary-200: var(--color-orange-200);
      --color-secondary-300: var(--color-orange-300);
      /* and so on ...*/
    }

    With Sass, you can run a quick loop and you’ll get these values quickly.

    $themes: (
      pink: (
        primary: pink,
        secondary: orange
      )
    );
    
    $color-tones: 100, 200, 300, 400, 500, 600, 700, 800, 900;
    
    @each $theme-name, $theme-colors in $themes {
      .theme-#{$theme-name} {
        @each $tone in $color-tones {
          --color-primary-#{$tone}: var(--color-#{map-get($theme-colors, primary)}-#{$tone});
          --color-secondary-#{$tone}: var(--color-#{map-get($theme-colors, secondary)}-#{$tone});
        }
      }
    }

    For Tailwind users, you could do a loop via a Tailwind plugin in v3, but I’m not quite sure how you would do this in v4.

    // The plugin code
    const plugin = require('tailwindcss/plugin')
    
    module.exports = plugin(function ({ addUtilities, theme }) {
      const splendidThemes = theme('splendidThemes', {})
      const palette = theme('colors')
      // Collect all unique tone keys used by any color in any theme
      const allTones = new Set()
      Object.values(splendidThemes).forEach(themeConfig => {
        Object.values(themeConfig).forEach(colorName => {
          if (palette[colorName]) {
            Object.keys(palette[colorName]).forEach(tone => allTones.add(tone))
          }
        })
      })
    
      const utilities = {}
    
      Object.entries(splendidThemes).forEach(([themeName, themeConfig]) => {
        const themeClass = {}
    
        Object.entries(themeConfig).forEach(([role, colorName]) => {
          if (!palette[colorName]) return
          allTones.forEach(tone => {
            if (palette[colorName][tone] !== undefined) {
              themeClass[`--color-${role}-${tone}`] =
                `var(--color-${colorName}-${tone})`
            }
          })
        })
    
        utilities[`.theme-${themeName}`] = themeClass
      })
    
      addUtilities(utilities)
    })
    // Using it in Tailwind v3
    module.exports = {
      plugins: [
        require('path-to-splendid-themes.js')
      ]
      theme: {
        splendidThemes: {
          pink: {
            primary: 'pink',
            secondary: 'orange'
          },
          blue: {
            primary: 'blue',
            secondary: 'purple',
            tertiary: 'orange'
          }
        }
      },
    }

    Will this generate a lot of CSS variables?

    Yes.

    But will in affect performance?

    Maybe, but I’d guess it won’t affect performance much, since this code is just a couple of bytes more. (Images, by contrast, weigh thousands of times more than these variables do.)

    And now we no longer need to worry about knowing whether background-1 or background-2 is the right keyword. We can simply use the semantic numerals in our components:

    .card {
      background-color: var(--color-primary-500)
    }
    
    .card-muted {
      background-color: var(--color-primary-700);
    }

    One More Note on Semantics

    I think most frameworks get it right by creating component-level semantics. This makes a ton of sense.

    For example, with Pico CSS, you can do this:

    Four CSS color variables named for utility, such as pico-card-background-color. Each variable is set to the value of another variable based on its type of color, such as pico-background-color.

    In your own creations, you might want to reduce the amount of namespaces (so you write less code; it’s less tedious, yeah?):

    .card-namespaced {
      --card-header-bg: var(--color-primary-600);
    }
    
    .card-without-namespace {
      --header-bg: var(--color-primary-600);
    }

    No “extra semantics” or even “namespacing” needed when the project doesn’t require it. Feel free to Keep It Simple and Sweet.

    This brings me to a separate point on component vs global variables.

    Global Variables

    Some variables should be global because they can propagate through the entirety of your site without you lifting a finger (that is, once you design the CSS variables appropriately).

    An example of this with borders:

    :root {
      --border-width: 1px;
      --border-style: solid;
      --border-color: var(--color-neutral-700);
    }

    You can change the global --border-color variable and adjust everything at once. Great!

    To use this sorta thing, you have to build your components with those variables in mind.

    .card {
      border: var(--border-width) var(--border-style) var(--border-color);
    }

    This can be easily created with Tailwind utilities or Sass mixins. (Tailwind utilities can be convenient Sass mixins).

    @utility border-scaffold {
      border: var(--border-width) var(--border-style) var(--border-color);
      border-radius: var(--radius);
    }

    Then we can easily apply them to the component:

    .card {
      @apply border-scaffold;
    }

    To change the theme of the card, we can simply change the --border-color variable, without needing to include the card-border namespace.

    .card-red {
      --border-color: var(--color-red-500);
    }

    This way, authors get the ability to create multiple variations of the component without having to repeat the namespace variable. (See, even the component namespace is unnecessary.)

    .pico-card-red {
      --pico-card-background-color: var(--color-red-500);
    }
    
    .card-red {
      --bg-color: var(--color-red-500);
    }

    Now, I know we’re talking about colors and theming, and we segued into design systems and coding… but can you see that there’s a way to create a system that makes styling much easier and much more effective?

    Well, I’ve been pondering this kinda thing a lot over at Splendid Labz, specifically in Splendid Styles. Take a look if you are interested.

    Enough tooting my own horn! Let’s go back to theming!

    I think here are some other values that you might want to consider in your global variables:

    :root {
      --border-width: ...;
      --border-style: ...;
      --border-color: ...;
    
      --outline-width: ...;
      --outline-style: ...;
      --outline-focus-color: ...;
      --outline-offset: ...;
    
      --transition-duration: ...;
      --transition-delay: ...;
      --transition-easing: ...;
    }

    How Important is All of This?

    It depends on what you need.

    People who need a single theme can skip the entire conversation we hashed out above because they can just use the color palettes and call it a day.

    .card {
      background: var(--color-pink-500);
      color: var(--color-pink-900);
    }

    For those who need multiple themes with a simple design, perhaps the stuff that Pico CSS, DaisyUI, and other frameworks have provided is sufficient.

    showing 20 CSS variables for colors with names based on scale, and utility. All variables are defined with the oklch color function.
    What it takes to create a DaisyUI Theme.

    Side Rant: Notice that DaisyUI contains variables for --color-success and --color-danger? Why? Isn’t it obvious and consistent enough that you can use --color-red for errors directly in your code? Why create an unnecessary abstraction? And why subject yourself to their limitations? Anyway, rant end. You get my point.

    For those who want flexibility and lots of possible color shades to play with, you’ll need a more robust system like the one I suggested.

    This whole thing reminds me of Jason’s Cohen’s article, “Rare things become common at scale”: what is okay at a lower level becomes not okay at a larger scale.

    So, take what you need. Improve what you wish to. And may this help you through your development journey.

    If you wanna check out what I’ve created for my design system, head over to Splendid Styles. The documentation may still be lacking when this post gets published, but I’m trying to complete that as soon as I can.

    And if you’re interested in the same amount of rigour I’ve described in this article — but applied to CSS layouts — consider checking out Splendid Layouts too. I haven’t been able to look back after I started using it.

    Have fun theming!


    Thinking Deeply About Theming and Color Naming originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous Articleastronaut – Gemini browser for the terminal
    Next Article Automate your project with GitHub Models in Actions

    Related Posts

    News & Updates

    LastPass can now warn or block logins to shadow SaaS apps – here’s how

    August 4, 2025
    News & Updates

    Get up to a year of Adobe Creative Cloud access for 40% off

    August 4, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Racing beyond DeepRacer: Debut of the AWS LLM League

    Racing beyond DeepRacer: Debut of the AWS LLM League

    Machine Learning

    CVE-2025-49592 – n8n Open Redirect Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Ubisoft blames gamers, Steam, trends, and everyone but itself for poor game sales

    News & Updates

    Don’t let cybercriminals steal your Spotify account

    Development

    Highlights

    CVE-2025-4800 – WordPress MasterStudy LMS Pro Arbitrary File Upload Vulnerability

    May 28, 2025

    CVE ID : CVE-2025-4800

    Published : May 28, 2025, 6:15 a.m. | 3 hours, 10 minutes ago

    Description : The MasterStudy LMS Pro plugin for WordPress is vulnerable to arbitrary file uploads due to a missing file type validation in the stm_lms_add_assignment_attachment function in all versions up to, and including, 4.7.0. This makes it possible for authenticated attackers, with Subscriber-level access and above, to upload arbitrary files on the affected site’s server, which may make remote code execution possible.

    Severity: 8.8 | HIGH

    Visit the link for more details, such as CVSS details, affected products, timeline, and more…

    CVE-2025-5820 – Sony XAV-AX8500 Bluetooth ERTM Channel Authentication Bypass

    June 20, 2025

    CVE-2025-5140 – Seeyon Zhiyuan OA Web Application System Server-Side Request Forgery Vulnerability

    May 25, 2025

    CVE-2025-49141 – HAX CMS PHP OS Command Injection

    June 9, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.