facebook / stylex

StyleX is the styling system for ambitious user interfaces.
https://stylexjs.com
MIT License
8.21k stars 304 forks source link

CSS Custom Property Inheritance Problem #566

Closed aspizu closed 1 month ago

aspizu commented 1 month ago

Was messing around with CSS custom properties and realized something which is impossible to do with them. The stylex API lets you describe this, but it doesn't actually work the way you would think it should.

tokens.stylex.ts

export const foo = stylex.defineVars({
    bar: "red"
})

export const biz = stylex.defineVars({
    boo: foo.bar
})

And, now using stylex.createTime:

app.ts

import stylex from "@stylexjs/stylex"
import {biz, foo} from "~/tokens.stylex"

const styles = stylex.create({
    foo: {
        aspectRatio: 1,
        background: biz.boo,
        width: "100px"
    }
})

const theme = stylex.createTheme(foo, {
    bar: "blue"
})

export function App() {
    return (
        <div {...stylex.props(theme)}>
            <div {...stylex.props(styles.foo)}></div>
        </div>
    )
}

Expected behavior

You would expect the box to be of color blue.

But, what actually happens is that it remains red.

nmn commented 1 month ago

This is how CSS variables work, so the way things work today is expected. The workaround is to create a theme to "re-set" the derived variable:

import stylex from "@stylexjs/stylex"
import {biz, foo} from "~/tokens.stylex"

const styles = stylex.create({
    foo: {
        aspectRatio: 1,
        background: biz.boo,
        width: "100px"
    }
})

const theme = stylex.createTheme(foo, {
    bar: "blue"
})
const themeBoo = stylex.createTheme(biz, {
    boo: foo.bar,
})

export function App() {
    return (
        <div {...stylex.props(theme, themeBoo)}>
            <div {...stylex.props(styles.foo)}></div>
        </div>
    )
}

This will do what you expect.

aspizu commented 1 month ago
export const color = stylex.defineVars({
    shadow: "0, 0, 0",
    shadowStrength: "0.1",
})

export const shadow = stylex.defineVars({
    md: `0 2px 2px rgba(${color.shadow}, ${color.shadowStrength}`,
})

Having to repeat stuff like this is bad. This should be patched in stylex itself.

defineVars could keep track of variables it depends on, then createTheme can patch them.

nmn commented 1 month ago

@aspizu This is a subjective issue as one behaviour isn't automatically better. After all, we're replicating the behaviour in CSS itself.

That said, we recognise how the CSS behaviour may not match expectations and have considered many possible solutions none of which seem to quite work. If you have a longer proposal on how the whole system should work, we're happy to consider your ideas.