stitchesjs / stitches

[Not Actively Maintained] CSS-in-JS with near-zero runtime, SSR, multi-variant support, and a best-in-class developer experience.

Home Page:https://stitches.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for CSS layers

viridia opened this issue · comments

commented

One of the problems with CSS-in-JS frameworks generally is that it's hard to control the cascade order. This often results in styles overriding each other in undesirable ways, for example your 'hover' style taking a higher precedence than your 'disabled' style. There are various workarounds, such as adding extra && to up the specificity, but these are just hacks.

The solution is to support CSS layers. The way I envision it, the list of layers would be passed into the createStitches() constructor. It would take a list of names in camel case, for example:

createStitches({
  layers: ['uiBase', 'uiVariants', 'uiStates'],
  ... etc.
)}

Once defined, the layers can then be used in any call to css():

const myCss = css({
  uiBase: {
    borderColor: 'red',
  },

  uiStates: {
    '&:hover': {
      borderColor: 'blue',
    }
  }

The CSS properties within the layers can use any of the syntax that is normally allowed in the css() call. From an implementation standpoint, this means that they layer names are merged in with the CSS argument keys just like variants and such. It is the responsibility of the caller to ensure that layer names don't conflict with any CSS property names.

CSS properties not wrapped in layers will work just as they do today. Because of the way CSS layers work, classes not wrapped in a layer have a higher precedence than any explicitly-named layer, which is what we want.

When the stylesheet is generated, layers would have the following effects:

  • The layer names would be converted to kebab-case.
  • The stylesheet would include a definition of layer order:
@layer ui-base, ui-variants, ui-states;
  • Class definitions would be output multiple times, once for the default layer (if there are any non-layered props) and once for each layer mentioned. All layers would be merged so that the @layer name would only appear once in the output.
.xx-1234 {
  border-color: blue;
}

.xx-4567 {
  border-color: red;
}

@layer ui-base {
  .xx-1234 {
    background-color: #ff0000;
  }

  .xx-4567 {
    background-color: #ff0000;
  }
}

@layer ui-states {
  .xx-1234:hover {
    filter: brightness(1.1);
  }

  .xx-4567[disabled] {
    opacity: 0.5;
  }
}

Note: while it is possible to use layers currently by simply treating them as media queries, it is not very efficient, because the @layer definition is treated like a selector expression, and is output separately for each individual CSS class that uses a layer - in other words, the layers are not merged, so the @layer is repeated many times.

commented

Never heard of those layers before, but interesting concept. However, I think stitches will not get any new features in the meantime (see #1144)