A CSS Framework is Required for Maintainable Web Design

One of the most popular questions posed by people who don’t use a CSS framework is, “What are the benefits of using a CSS Framework?” On some level, that question reflects a lack of CSS knowledge in the first place.

That’s not meant as an insult, of course. It’s just that the base knowledge needed to write functional CSS and the conceptual knowledge required to write maintainable CSS are very different. A person can have decent functional CSS skills, but that’s only half the battle, or less, in web design.

Someone with adequate conceptual knowledge required to write maintainable CSS would never ask, “Why use a CSS framework?” So, even asking that question reveals a gap in knowledge and understanding.

With that said, the premise of this article is simple: If you want to write maintainable CSS, you must use a framework.

Wait! Hold up. You probably lept to assuming that I meant this: If you want to write maintainable CSS, you must use a commercial CSS framework. That’s not what I said – just so we’re all on the same page.

Let’s use an insanely simple example to prove the premise. This will also reveal the answer to the question, “Why use a framework?” for those asking.

Style this link into a button.

Here’s a link:

<a href="#">Sample link</a>
Code language: HTML, XML (xml)

You need to make that link to look like a button.

Here’s one method you might try:

<a href="#" style="background-color: #6cceb3; padding: .5em 1em; line-height: 1; color: #1a2c3f; text-decoration: none; border-radius: 5px;">Sample link</a>
Code language: HTML, XML (xml)

This is called “inline styling,” and it has significant disadvantages. But it’s functional because it works to create the desired effect.

Here’s a more traditional approach:

<a class="btn" href="#">Sample link</a>

.btn {
	background-color: #6cceb3;
	padding: .5em 1em; 
	line-height: 1; 
	color: #1a2c3f; 
	text-decoration: none;
	border-radius: 5px;
Code language: HTML, XML (xml)

We used a class that allows us to apply this style to any other links we want. And all buttons now have a single source of truth.

Now, let’s look at a third approach:

<a href="#" class="bg-[#6cceb3] py-2 px-4 color-[#1a2c3f] no-underline rounded-md leading-none">Sample link</a>
Code language: HTML, XML (xml)

This is called a “utility-first” approach that uses classes with predefined styles to achieve the look (and, in this case, a couple of custom styles for the colors).

So, right off the bat, we see at least three fundamentally different approaches to arriving at the same place, all with wildly different pros and cons.

And there are still two major issues here.

  1. We need to plan how to support multiple button styles (because almost every site uses more than one button style).
  2. We need to plan how to replace static color references with tokens (because littering static hex codes everywhere is what I call a CSS “ecospill”).

Since the inline approach is almost universally accepted as dumb, and the utility-first approach requires a framework (literally), let’s keep marching forward using the traditional approach.

Supporting a secondary button style

Demonstration of multiple button styles

Since almost all websites use multiple button styles and you likely want to maintain some semblance of consistency between projects, you must plan how to support that.

First, you must decide what you’ll name the secondary button style. Will you name it “secondary,” “alt,” “two,” or something else?

“Secondary” is good, but it’s long. It also might clash with a “secondary” color in your [currently unplanned] color system.

“Alt” is shorter and easier to type, but what if there’s more than one alternate style? How many styles do we need to support?

“Two” is elementary and has no meaning. Let’s agree that was a bad idea and move away from it.

Since “secondary” is also commonly used in color systems, and you don’t want to create confusion between a button style and a specific color, you should probably go with “alt.”

Now you need to decide how you’ll apply the alt style. Here are some options:

<a class="btn alt" href="#">Sample link</a>
<a class="btn-alt" href="#">Sample link</a>
<a class="btn--alt" href="#">Sample link</a>
<a class="btn btn--alt" href="#">Sample link</a>
<a class="btn btn-alt" href="#">Sample link</a>
<a class="btn" data-button-style="alt" href="#">Sample link</a>
Code language: HTML, XML (xml)

Do you know what the pros and cons of each of these approaches are? Is it apparent how each approach will be executed in the stylesheet? Here’s a quick rundown:

  • btn alt assumes that all shared styles are assigned to .btn and the non-shared alternate colors are assigned to .alt. But, this has two issues: increased specificity (.btn.alt) and an “alt” class that means nothing by itself.
  • btn-alt assumes that all shared and alternate button styles are assigned to the .btn-alt class. This raises efficiency and shared style concerns (it’s not DRY).
  • btn--alt is a nod to BEM methodology. There could be similar concerns for efficiency and shared styles as in the previous example, but the BEM modifier extension (–) could be used to overcome this using a class selector like [class*="btn--"].
  • btn btn--alt is traditional BEM and btn btn-alt is some sort of “I hate double dashes” BEMishness. The global styles are assigned to .btn and the alt styles are assigned to the second class. This approach differs from option #1 in that the second class is obviously used within the context of buttons, making it easier to read, understand, and remember across a full-scope project. Additionally, this keeps the CSS flat, so you’re not increasing specificity to get the alt styles.
  • .btn[data-button-style="alt"] uses a data attribute to assign the alternate styles. This begs the question, “Why?” while also raising readability and efficiency concerns. It’s less efficient to type than any other method and is incredibly time-consuming in a page builder environment. It also potentially increases specificity, similar to the first example, but not necessarily.

I don’t care which one you choose, though I know which one I’d choose.

The point is this: The simple fact that you’re even considering these things means you’ve switched gears from working to frameworking.

If you don’t take the time to consider these things, there’s a 100% chance that the CSS on your projects is going to get, shall we say, messy. On projects of any real size, “messy” becomes “nightmarish” pretty fast.

Let’s keep going.

Oh no, papi! You’re not using static color references, are you?

.btn {
	background-color: #6cceb3;
	padding: .5em 1em; 
	line-height: 1; 
	color: #1a2c3f; 
	text-decoration: none;
	border-radius: 5px;
Code language: CSS (css)

Using static colors is unmaintainable and inefficient. It’s much better to use global variables.

But you can’t just “use global variables” without considering what you’ll name them. And by “them,” I mean “all of them.”

Here are some options based on those hex codes:

  • var(--color-1) & var(--color-2)
  • var(--mint) & var(--dark-blue)
  • var(--mint-500) & var(--blue-100)
  • var(--action) & var(--base)

I’ve seen all these approaches used. Here’s a simple explanation of each with some quick thoughts.

  • var(--color-1) & var(--color-2) – This is a pretty terrible approach. These names mean nothing, and if you take more than a 72-hour break from the project to work on something else, you’ll have no clue what color they reference when you return.
  • var(--mint) & var(--dark-blue) – This is a literal color name approach. It’s pretty terrible because brand colors often change, and these tokens become out of sync the minute that happens.
  • var(--mint-500) & var(--blue-100) – These names assume the use of a shade system, but the same cons from the step above apply to this system, too.
  • var(--action) & var(--base) – This is my preferred approach, but with one extra step that we’ll discuss next. These names semi-describe what each color is being used for and remain flexible should the actual color value ever need to change.

And here’s what your code might look like after setting up some simple color tokens:

.btn {
	background-color: var(--action);
	padding: .5em 1em; 
	line-height: 1; 
	color: var(--base); 
	text-decoration: none;
	border-radius: 5px;
Code language: CSS (css)

This is much more maintainable. But, remember that your color system has to be flexible and scalable. Shades and transparencies will come into play on almost every project, so the syntax must also support this.

Here’s how it works in Automatic.css for the Action color:

  • action
  • action-ultra-light
  • action-light
  • action-medium
  • action-dark
  • action-ultra-dark
  • action-hover
  • action-trans-[10-90]
  • action-light-trans-[10-90]
  • action-dark-trans-[10-90]
  • action-ultra-dark-trans-[10-90]
  • action-h
  • action-s
  • action-l
  • action-r
  • action-g
  • action-b
  • action-hsl
  • action-rgb

But, that’s just names! What about color space? Using hex codes would be absurd.

Are you going to map all this through HSL? RGB? Lab? HWB? CIE? How will you manage the relationships and partials? Will you be using the new color-mix() function at all? And how will you manage this as color spaces in CSS change?

Perhaps you should meander through some of the Level 4 CSS Color Module documentation just to get a little taste of what there is to consider.

If you use a framework like Automatic.css, all the thinking and technical setup is already done for you and there’s even a simple UI for adjusting all this stuff.

Here’s the rub. If you don’t use a framework like Automatic.css, that doesn’t mean you’re not using a framework! This takes us back to the original premise: You’re either using a framework or you’re doing CSS incorrectly.

Look at everything we’ve talked about so far. You’re either thinking deeply about this stuff and setting up your project logically (frameworking!), or you’re writing messy, nightmarish, unmaintainable CSS.

I confidently say this because you don’t just trip and fall into a maintainable stylesheet. This stuff is either deeply considered, or it’s a mess.

The only valid question related to CSS frameworks is: Will you use an existing framework or do all the work to create and manage your own? Not frameworking isn’t really an option for a professional.

Now, before you answer that, let’s keep going:

Can you build in far more flexibility to your buttons?

Here’s how button code looks in ACSS:

[class*="btn--"] {
	background-color: var(--btn-background-color);
	padding: var(--btn-padding-block) var(--btn-padding-inline); 
	line-height: var(--btn-line-height); 
	color: var(--btn-text-color); 
	text-decoration: var(--btn-text-decoration);
	border-radius: var(--btn-border-radius);
}Code language: CSS (css)

There’s actually much more to it than that, but you get the idea. Now, compare that to the code we’ve been using thus far.

All property values are mapped to locally scoped variables, many of which are simple and meaningful abstractions for other variables within the framework (like color & spacing variables). This allows you to use buttons in a simple, typical fashion or “theme” buttons with shared global styles for maximum efficiency and flexibility.

Button styling is controlled from the ACSS dashboard, so you never have to look at the code. But, should you need advanced flexibility in your buttons, all the necessary tokens are there for you. It’s all been thoroughly philosophized and scrutinized, resulting in what is probably the most efficient and flexible button system available anywhere.

Again, these are not just methodologies you stumble into. They come from hundreds of hours of frameworking.

And that’s just buttons, my boy!

I just spent 1600 words talking about maintainable button CSS. What a nerd.

And guess what?

  1. Buttons are easy!
  2. I didn’t even go as deep as we could have.
  3. There are approximately 289094 more things on the CSS list we still have to framework.

So, let’s revisit the premise: You’re either working or you’re frameworking.

Using an existing framework like Automatic.css allows you to spend your time working in the most efficient and maintainable way possible.

Not using an existing framework means you must spend a lot of time frameworking. And this isn’t just about coming up with a framework in the first place; it’s about ease of use and maintenance.

ACSS has features and workflow enhancements that most people can’t build themselves, sitting on top of a framework that can’t be matched without investing hundreds of hours of consideration and development time.

If the idea of engineering and philosophizing about CSS to the point at which your brain runs through calc() and var() strings in your dreams, then frameworking might be a great path forward for you.

If you’d rather spend your time checking off project requirements as efficiently and effortlessly as possible while building fully maintainable sites and then cashing checks from clients, then I’d suggest you use an existing framework.

If you’re doing your work in WordPress or a page builder, then ACSS is the #1 choice by far.

Just remember, you’re either working or you’re frameworking. And ain’t nobody paying you to framework.

join the conversation


  • This is an excellent article that highlights a very real issue. But it’s not a button issue. It’s not even a CSS issue. It’s a thinking issue. In the end, what you’re demonstrating, in this well articulated post, is that if you don’t know or haven’t learned to abstract when problem solving, you’re never going to get to that next level. The difference between decision makers who win, and those who keep busy on the most boring and mundane of issues, is the ability to think abstractly. Your use of CSS as the playground for that abstract thinking is a great example. And you’re right, it’s bigger than just buttons. But it’s also much bigger than CSS. Thankfully, when it comes to CSS, it’s clear you’ve handled it.

  • I started developing my own CSS framework in 2020 and then I discovered Automatic CSS. I quickly ditched what I started and embraced ACSS. Today I wouldn’t consider building a website without ACSS.

  • Eduware

    Thanks for breaking things down. I will not be building a CSS framework, but do like to read about the internal workings compared to working without it. This really solidifies the reason to work with one vs without.

    Have a nice day!

  • Is this available for other platforms or use with vanilla css?

    • A

      It’s currently only for select WordPress page builders.

      • I have seen the ACSS dashboard but have never used it. The UX looks great in the videos. Would it be possible for you to launch a web dashboard where we can generate automatic CSS stylesheets?

Leave your comment

Kevin Geary

Kevin is the CEO of Digital Gravy, creator of Automatic.css, creator of Frames, and a passionate WordPress educator. If you're interested in learning directly from Kevin, you can join his 1500+ member Inner Circle.

More articles like this

related posts