MelangeCSS

Current Version: 1.0.0-RC4

But…Why?

Why Utility Classes?

If you have never used a CSS library like this, it probably seems ridiculous. It seems that we are mixing content and presentation, that we are avoiding using CSS as it was intended, creating unsematic markup, or otherwise making a soup of characters that no one could possibly manage. You may also think this is just a short-hand for inline styles.

Let's take these one at a time.

Mixing content and presentation. There's no denying that placing a class like bg-purple-500 inside HTML is putting visual instructions into the markup. It's worth understanding why this feels like a problem. If the same markup is intended to produce many different visual representations then, yes, mixing presentation instructions into the markup makes it hard to manage. When we build web applications, however, we are rarely doing this.

Most web applications deliver a specific user experience, usually with some slight modifications on different screen sizes. This is not the “CSS Zen Garden” approach and very few web apps need that. If they do, MelangeCSS is not for them. But for most apps, it turns out that putting styling instructions in the markup makes some things easier.

When you open an HTML file and see <a href="/" class="blue-400 f-3">link</a>, you can see that the link is rendered in the third sized font in the dark blue color. If, instead, the value for class was something more abstract like primary-link it would be harder to figure out how that link renders in a browser. Depending on what CSS is included on the page, it could be extremely hard.

These classes are not semantic. The class attribute is ignored by most screen readers. Users who are not viewing your app in a traditional web browser will get semantic information from the tags used. The app can make use of ARIA roles to further clarify. The class attribute is irrelevant. There is no reason or benefit to making its value have semantic meaning. It is entirely a hook for styling.

The terse names are an unmanageable, nonsensical mess of characters. Any verbose code in any programming language can be abstracted or simplified through the use of functional decomposition. Your web app is no different. You can use its templating system to extract re-usable code, when you want, not before.

The terse class names can be hard to learn at first, because a class like fw-4 doesn't seem immediately obvious. But, if you know CSS, understand the naming conventions, and use MelangeCSS for just a small amount of time, you will learn these class names. And you will start to go much faster, because you won't rely on autocomplete or flipping back to the documentation.

Why not just use inline styles, then? MelangeCSS has four differences from inline styles.

  • The class names are far shorter than their analogous CSS properties and values. Even with sophisticated auto-compete, typing out these terse classes is faster.

  • Inline styles cannot target media queries to allow for responsive design.

  • Inline styles have a higher specificity, so they can still use used alongside classes if needed.

  • Most importantly, Melange includes a grid-based design system. While you can use custom properties in inline styles, it's far more difficult than using classes based on a design system (based on custom properties).

Being able to design and style by selecting from a small set of values vastly increases the speed at which you can produce styled views. You can quickly iterate through all possible spacings, font sizes, or widths and choose the one that works. Yes, you lose the flexibilty of using any of the infinite possible sizes, but you usually don't need that many.

As a demonstration, here are all the buttons you can make with changes to border radius. Surely, one of these will work for you?

Why Are There Limited Values?

A utility CSS framework only truly shines when it's coupled with a design system. That means that for any property whose values are essentially infinite, the design system provides a much smaller subset of values, usually 7 or 8.

This means that, when designing and building a UI, you don't have to make nearly as many decisions. You don't have to decide if text in 12, 13, 14, or 15 points is correct. You probably will choose between a few sizes: small, body, and larger.

Since you are using CSS, you can certainly create special-purpose classes for situations where the design system isn't sufficient. You can even leverage MelangeCSS's naming conventions if you need to add a new step to a scale.

If the CSS framework instead allowed any value to be specified with a single-purpose class (which is what TailwindCSS does), the CSS becomes quite large. You will need to design a language to abstract CSS and implement a build step. Both of these things slow you down and create carrying costs for your project.

Doesn't TailwindCSS Already Exist?

TailwindCSS is a popular utitlity-based framework, but it is fundamentally different from MelangeCSS. Tailwind allows you to set just about any property and value directly in your HTML. It achieves this by not having a design system and by requiring a development-time build step to produce CSS based on classnames like bg-[4477FF]. This build step must be run on every change of every file that could possibly contain a Tailwind class.

Because Tailwind has no design system, it is a very large library. The build step additionally strips out any classes that aren't used. This is a nice feature, however it's fragile and slow, especially compared to having no build step at all.

This doesn't mean Tailwind is bad, it's just making a different set of tradeoffs. MelangeCSS wants to provide a static set of CSS you can use for most situations and with a few dependencies as possible.

Isn't this Just Tachyons But Slightly Different?

I am a heavy Tachyons user. I love it, but in real projects there are a few things that are difficult:

  • There's no easy way to override the CSS variables without using the SASS version, and I don't want a build step.
  • The class names aren't as consistent as I would like. For example, the largest font size is 1, but the smallest spacing is also 1.
  • Augmenting Tachyons in a specific project with additional classes that leverage both the design system and breakpoints is not easy to do, or at least not as easy as I would like. For example, if I need an additional color, I'd like that color to conform to Tachyons' naming conventions, but achieving this requires basically hand-jamming all the class names.

I considered forking or making PRs for Tachyons to address this stuff, but I don't know if this would benefit Tachyons. It would certainly break things for existing users and that's never a good thing to do.

I also wanted to see what would be involved in having the CSS generated from a model in code, so this started as an experiment in producing a Tachyons-like CSS framework from code. By the time I had prototyped it, I figured why not complete it?