Getting to grips with CSS variables

I went a little colour crazy on the rebuild — categories, services, my portfolio, each are colour-coded. I was styling each one the hard way - type by type, element by element - so here's the CSS variable pattern that got me from 150+ lines of CSS down to about 20.

Affiliate Disclosure
This post may contain affiliate links (†). If you purchase a product through these links, BlueMoonCreative.Services may earn a small commission at no extra cost to you.
For further information, please read our Terms & Conditions of Use.

How this came about…

Bored with the minimalist look, I decided to go a little colour crazy on the BMCS rebuild. Every one of the eight categories on this site — AI, Business & Marketing, Code Snippets, and so on — has its own colour. It shows up on category page headings, “Feature Categories” sections, “Related Tags” sections, the black hole backgrounds and then on a number of single post elements — There are at least a dozen different elements across the site that all need to know “what colour is this category” and style themselves accordingly. Who knew CSS variables was the way to do that?

Now is not the time to reason why, theirs but to colour and comply. Said no-one, ever. Anyhow, moving on…

The colour system…

Nothing complicated here: eight additional brand colours, one per category plus one of the standard brand colours for the summary “Feature Articles” catch-all. The interesting part isn’t the colours themselves — it’s how I got every one of those dozen-plus elements to actually use them consistently, without me individually styling each combination.

The problem…

From the start, I was doing this the novice way (well you have to start somewhere): for every element that needed a category colour, I’d write a separate CSS rule per category. Here’s what that looked like for something as basic as the category link styling on blog post cards…

.ast-blog-single-element.ast-taxonomy-container.cat-links a {
    text-transform: uppercase;
    font-weight: 700;
}
.category-blog .ast-blog-single-element.ast-taxonomy-container.cat-links a {
    color: var(--ast-global-color-2);
}
.category-business-marketing .ast-blog-single-element.ast-taxonomy-container.cat-links a {
    color: #B07FA0;
}
.category-code-snippets .ast-blog-single-element.ast-taxonomy-container.cat-links a {
    color: #2E8A7C;
}
/* ...and so on for the remaining 5 categories (excluding AI at this point) */

That’s eight nearly-identical rule blocks to colour one element. And I had that same pattern repeated — with minor variations — for each of the elements to which I wanted to highlight the category. Multiply eight lines by a dozen-plus elements and you can see how the stylesheet ballooned past 150 lines just for category colouring, most of it the same eight-way repetition with a different selector on the front.

The actual trigger for fixing it was nothing to do with elegance or best practice, it was because it was a pain in the backside to manage. Adding an additional category (AI, added after the original seven) meant hunting through every one of those repeated blocks and adding a new line to each. Miss one, and that element silently falls back to the default colour — not broken exactly, just wrong, and easy not to notice.

The solution…

I knew full well this was not the best way to get the desired result, so I asked Claude for some guidance on restructuring this – these AI tools have their uses. I tested some of Claude’s suggestions to update this, as I wanted to understand them properly, rather than just copy something that looked right. The end result was creating a category-colour mapping as a single custom property, defined once per category, rather than repeating hardcoded values inside every consuming rule.

First, the actual category colours, are defined once at the root…

:root {
	--bmcs-global-color-1: #2D5F99;
	--bmcs-global-color-2: #B07FA0;
	--bmcs-global-color-3: #4A8F62;
	--bmcs-global-color-4: #5578AA;
	--bmcs-global-color-5: #C26848;
	--bmcs-global-color-6: #8F4042;
	--bmcs-global-color-7: #2E8A7C;
	--bmcs-global-color-8: #7B6DBF;
	--bmcs-global-color-9: #647AAA;
	--bmcs-global-color-10: #C98F74;
}

Then, a single “category colour map” block that assigns a –category-color variable per category, scoped to whichever selector context applies — in this case, the body class WordPress adds for category archives…

/* Category Color Map */
.category-business-marketing {
	--category-color: var(--bmcs-global-color-2);
}
.category-code-snippets {
	--category-color: var(--bmcs-global-color-7);
}
/* ...and so on for each remaining category */

That’s it — that block is the entire mapping, written once. Every element anywhere on the site that needs to be category-coloured just references var(–category-color) and lets the cascade sort out which value applies based on context. The cat-links example from earlier collapses from nine rule blocks down to this…

.category .ast-blog-single-element.ast-taxonomy-container.cat-links a,
.tag .ast-blog-single-element.ast-taxonomy-container.cat-links a,
.search .ast-blog-single-element.ast-taxonomy-container.cat-links a {
	color: var(--category-color);
}

One rule. No per-category repetition. The element doesn’t need to know which category it’s in — it just asks for “the category colour” and trusts that whatever’s above it in the DOM has already set that variable correctly. And, as you can see, I could also apply it to the tag and search archives too.

The benefit…

Once I understood how straightforward it was, I could apply it to single post elements (by adding a supplementary body class, ‘single-category-xxxx’), and even the home page (via JetEngine listing grid’s post ID attribute)…

/* Category Color Map */
.category-business-marketing,
.single-category-business-marketing, .jet-listing-grid__item[data-post-id="16"] {
	--category-color: var(--bmcs-global-color-2);
}
.category-code-snippets,
.single-category-code-snippets, .jet-listing-grid__item[data-post-id="17"] {
	--category-color: var(--bmcs-global-color-7);
}
/* ...and so on for each remaining category */

It is the line-count drop that is the obvious win — that one styling pattern alone went from around 150 lines of repeated per-category overrides down to roughly 20: the eight + one colour definitions plus the one-time category map block. Every element consuming var(–category-color) afterward adds just a single line, not eight.

But the bigger benefit was structural, not just shorter code. Adding the eighth category (AI) into the finished system meant adding one new block to the map — done, every single element picked it up automatically, nothing else to touch. It also meant I could follow that exact pattern for the services custom content type and portfolio custom post type. It just meant adding a colour mapping block for services and for portfolio…

/* --Services-CCT-Colors-- */
/*
	* Source: CCT bmcs_services > services_color field
	* Pattern: .jet-listing-grid__item[data-post-id="X"] { --services-color }
*/
/*	Web Design */
.jet-listing-grid__item[data-post-id="1"] {
	--services-color: #2D5F99;
}
/*	e-Commerce */
.jet-listing-grid__item[data-post-id="2"] {
	--services-color: #B07FA0;
}
/* ...and so on for each remaining service */

Portfolio posts required a bit more depth, needing a primary and a secondary color to form a gradient. To handle this, each new portfolio item simply gets its own two-variable line added to the mapping block…

/* --Portfolio-CPT-Colors-- */
/*
	* Source: CPT portfolio > primary_color / secondary_color fields
	* Pattern: .jet-listing-grid__item[data-post-id="X"] { --portfolio-primary-color / --portfolio-secondary-color }
	* Add a new block below each time a portfolio item is published.
*/

/*	IIP */
.jet-listing-grid__item[data-post-id="3865"], body.postid-3865, .post-type-archive-portfolio .post-3865 {
	--portfolio-primary-color: rgb(40,0,59);
	--portfolio-secondary-color: rgb(51,0,128);	
}
/*	MEM */
.jet-listing-grid__item[data-post-id="3866"], body.postid-3866, .post-type-archive-portfolio .post-3866 {
	--portfolio-primary-color: rgb(131,200,103);
	--portfolio-secondary-color: rgb(34,72,108);	
}
/* ...and so on for each remaining portfolio post */

Now, whenever a new portfolio post drops, I just add the relevant post ID selectors with those two specific colors. Every consuming element on the page looks after itself by pulling from var(–portfolio-primary-color) automatically.

Was using CSS variables the right solution?

The answer is actually Yes and No.

Yes, in the sense that it fits neatly with what I already have in place — a CSS custom property approach that gave me most of the benefit (single source, easy to extend, no duplication) without needing to change anything else about how the site’s built.

No, in the sense that this is exactly the kind of problem tools like Core Framework or Tailwind are purpose-built to solve using utility classes. While I missed an opportunity to experiment with those tools here (as I’ve been looking at them for a while), the reality is that retrofitting a utility-first framework onto an existing WordPress / Astra / Elementor stack wasn’t realistic. CSS variables gave me the architectural win I needed without forcing me to tear down my entire setup.

What it does highlight however, (skipping over the technical ineptitude) is that there are often several options available to achieve the same/similar result. And it is only through a little experimentation or research that we find the one that follows best practice or best suits our requirement at the time.

Disclosure: This article was drafted & written by the post author, with AI used as an assistive tool during the process — e.g. to explore ideas, check facts, or suggest phrasing. Final content has been edited, reviewed, & verified by the post author, who holds full editorial responsibility for the content published.
AI Assisted Icon

Look no further than BlueMoonCreative.Services website to see the results of this incredible toolkit in action. Crocoblock integrates seamlessly with our theme & plugins providing all the tools required to, easily & quickly, add dynamic content to our customised pages.
† Affiliate Promotion

Scroll to Top