Feature | Example | Standards-only approach |
---|---|---|
Nested selectors | Sass Style Rules | CSS Nesting Module Level 3 |
Importing (Coupling, from JavaScript, dead code removal) |
webpack css-loader | @import Cascading Stylesheet Module scripts (2) |
Bundling | webpack | Multiple stylesheets per file |
Variables | Sass Variables | CSS custom properties (variables) |
Calculations | Sass operators and functions | CSS calc |
Composition (class names only)1 | Sass @extend CSS Modules composes |
Issue: Multiple classes, source order, code splitting class order issues |
Automatic vendor prefixes | ||
Scoping | BEM CSS Modules |
BEM CSS Scoping Module Level 1 Declarative CSS Module Scripts |
Defining in JS | CSSinJS | Constructible StyleSheets adoptedStyleSheets |
Colocation | CSSinJS | |
Typing | CSSinJS | |
Manipulating in JS | CSSinJS | CSS Object Model |
Theme specification | System UI (2) | |
Style props | Atomic Styled system Sprinkles |
|
Composition (merging attributes)1 | tailwind-merge Vanilla Extract StyleX |
|
Merging1 at runtime | Sprinkles StyleX |
|
Variants | Styled System Stitches |
Naming convention, such as BEM |
Compound Variants | Stitches | Combining classes |
Responsive Variants | Stitches | .md- classes (bloat) |
Static extraction | Vanilla extract |
Footnotes
-
Composition vs. Merging
The Sass@extend
rule happens at the point when the component styles are written. Given two classes, class1 and class2, the order in which we extend them does not impact the order individual rules are applied.
Imagine<button composeClassNames={['class1', 'class2']} />
, how would you ensure all styles from class2 would override styles from class1?
Atomic CSS deals with this by having a single CSS class per CSS property and removing the CSS classes at consumption, depending on composition order. ↩ ↩2 ↩3