Styling
Layers

Layers

CSS recently introduced a new feature called layers to the cascade specification (opens in a new tab).

This important feature allows more granularity and control over CSS specificity and overrides, especially when discussing shared libraries and design systems.

Layers allow authors and Lualtek UI consumers to define specificity layers independently from when a specific style appears on the page and the parsing order.

Here is a quick example, in the code below, if we remove the @layer reset declaration the p element would be blue. Still, since the browser parses the CSS placed outside any layer (implicit final layer) after all the styles coming from layers, the p element is red even if p[data-blue] has higher specificity.

p {
  /* specificity of 0,0,1 - implicit (final) layer */
  color: red;
}
 
@layer reset {
  p[data-blue] {
    /* specificity of 0,1,1 - explicit "reset" layer */
    color: blue;
  }
}

Lualtek UI layers

Lualtek UI defines 6 CSS layers, referenced internally inside the packages that compose the design system:

@layer core, utilities, plain-components, components, overrides, themes;

Let's see a real example. The Button component declares its styles inside the components layer:

@layer components {
  .Button {⋯}
}

Now, the Snackbar needs to override some properties of the button, but we cannot use (opens in a new tab) !important. Layers come to rescue by allowing us to section the cascade in different layers of specificity. Now let's see what the Snackbar can do to solve this issue.

@layer overrides {
  .Action {
    color: var(--snackbar-bg);
    background-color: var(--snackbar-fg);
 
    &:is(:active, :hover) {
      color: var(--snackbar-bg);
      background-color: var(--snackbar-fg);
      opacity: 80%;
    }
  }
}

Since we declared the overrides scope after the components layer, it has higher precedence in the cascade and specificity computing. This way, the styles declared inside a layer overrides will win over the ones declared inside the layer components. This is the same as using !important but without the drawbacks. Additionally, any style not declared inside a layer will be placed inside the implicit (final) layer, which has the highest precedence in the cascade and so will win over any other layer.

Advantages for consumers

When consumers need to write down their styles and overwrite some properties, any CSS defined in their project will always win over the styles coming from the design system unless the user declares them inside a new and local CSS layer.