The idea is to combine the best bit of global styling (reuse, small payload) and local styling (total isolation, first-class React syntax)
This is combined with the concept of traits: you can think of them as permitted property/value pairs. Instead of every component being able to have every CSS property available to it, you can reduce your permitted set to X font families, Y font-size + line-height pairs, Z foreground/background colour pairs, W padding amounts. This is based off my work using amcss on real projects — traits were the single key feature that kept me using AM.
The one-sentence explanation: A site defines a set of permitted visual features, all components are simply a combination of those features
@define-trait X
establishes X
as a type of trait. These include the above mentioned concepts: typography, colouring, spacing, layout, etc.
Any CSS inside a @define-trait :default
block are shared by all users of that class. If a trait was button
, this would be all the default styling for a button.
Any sub-rule under a trait indicates a trait variant. These get turned into classes, and components mix them in. E.g. the variant vertical
of trait flex
gets turned into the class .t-trait--vertical
.
:local
exports local
to React, which is a set of classnames that include an auto-generated class-name for any one-off CSS if needed, plus any traits it includes. Using that in React is dead simple.
Inside a :local
expression, a &
block will allow arbitrary CSS to be written. That will be extracted into a one-off class.
Using traits inside a :local
block should be the main way you include styles. The syntax is like pure css: trait: variant-a variant-b;
.
Well, I think I'm working backwards from the one actually new idea here — exporting tokens from CSS to JS. I love the approach already in @sokra and @markdalgleish's work, but exporting only a single class from CSS to JS seems like a waste. I really like the idea of exporting atomic classes — if you treat classnames on elements as the compilation target of whatever fancy shit you're trying to do, you get decent semantics (the class names dont need to be obfuscated to begin with) and absolutely the best-possible performance. @necolas just sketched out a similar idea, going from JS to CSS instead.
So, the trait thing is orthogonal to the exporting thing, but in my head they go nicely together. So how about we come up with a standard for the exporting first, that both webpack and JSPM can build upon, and could be one day turned into a CSS spec proposal:
So, current
css-loader
syntax is simple:Same thing for
postcss-local-scope
:My trait idea here ends up generating:
A couple of my thoughts on the exact syntax:
.className
not"className"
, and multiple classes should be.classOne.classTwo
not"classOne classTwo"
. This means an additional transformation is required to consume this in React, but it's dead-simple.@export
rules should be able to anywhere at the top-level in the file (i.e. not nested, but not required to be the first statement in the file).If we agreed on a standard, it would make interop between Webpack, JSPM & Browserify easier, and let me do my Trait idea and let other people do their own multi-export ideas as PostCSS transforms.
Thoughts?