Public and private CSS cascade layers in a design system



This content originally appeared on Go Make Things and was authored by Go Make Things

One of the most important native modern CSS features I’m using in Kelp UI is cascade layers and the @layer at-rule.

Today, I wanted to share how I use a mix public and private cascade layers in Kelp to provide CSS hooks for developers. Let’s dig in!

(If you haven’t read my article on cascade layers yet, start there or this article won’t make sense.)

A wrapper layer

The entire Kelp UI library is wrapped in a kelp cascade layer.

This let’s developers more easily control the cascade order of Kelp versus other CSS they’re loading. It also means that global CSS will take priority over Kelp, regardless of the order in which it was loaded.

(As a general rule with cascade layers, CSS that’s not in a layer is loaded into the cascade after any code that is, making it the “last defined value” for any particular selector.)

If you’re working with third-party libraries that don’t use cascade layers, you can add them to a layer using the @import operator.

@import "https://some-awesome-third-party-tool.css" "third-party-layer";

Private APIs

The concept of private methods and private APIs is really common in the JavaScript.

A JS library might have some internal methods that are used inside the library, but not documented and not intended to be used outside of it. They might change over time, and are abstractions or implementation details rather than user-facing tools.

API libraries do this a lot, too.

They’ll have a whole suite of public-facing endpoints, but every now and then a developer will discover an undocumented private API that’s used by the API vendor, but not intended for public use. The in-code comments will often mention that it can break at any time and shouldn’t be used.

I apply this same concept to Kelp and cascade layers.

Public and private cascade layers

Kelp currently has 11 internal layers.

@layer kelp;
@layer
	kelp.palette,
	kelp.base,
	kelp.theme, /* ! */
	kelp.core,
	kelp.extend, /* ! */
	kelp.layout,
	kelp.utilities,
	kelp.tokens,
	kelp.overrides, /* ! */
	kelp.state,
	kelp.effects; /* ! */

Most of these are private. Only the ones with a bang next it (!) are intended for public use.

  • kelp.theme – Use this layer to override default theme styles.
  • kelp.extend – Use this layer to add new features and styles to Kelp.
  • kelp.overrides – Use this layer to override existing Kelp styles.
  • kelp.effects – Use this layer to add or override state-based effects (like :hover or :active).

This is is what allows Kelp to be customized without any sort of build step. As long as you put your customizations in the correct layer, the browser will layer them in the right place to take full advantage of the cascade.

Examples

Let’s say I wanted to change the primary font from the current stack (system default) to Open Sans.

I’d add that to the kelp.theme layer, like this…

@layer kelp.theme {
	:where(:root) {
		--font-primary: 'Open Sans', sans-serif;	
	}
}

If I wanted to update the default padding on the .callout component to make it bigger, I would do that in the kelp.extend layer, like this…

@layer kelp.extend {
	.callout {
		padding: var(--size-m);
	}
}

And if anything I was doing required adding or modifying some sort of effect, like :hover, I would do that in the kelp.effects layer.

@layer kelp.effects {
	.link-awesome:hover {
		color: var(--color-hover);
	}
}

Embrace the cascade!

What I love about cascade layers is that they let me take full advantage of the cascade.

A lot of modern UI tools work really hard to fight against it or reduce it’s impact. That’s a big part of Tailwind’s selling point. That’s what shadow DOM evangelists most often tout as it’s key feature. It’s what scoped components in React and Vue are all about.

Kelp has a different perspective: the cascade is good, actually.

I want to use it as much as possible, and the @layer at-rule lets me do that extremely effectively!

Like this? A Lean Web Club membership is the best way to support my work and help me create more free content.


This content originally appeared on Go Make Things and was authored by Go Make Things