postcss / postcss-simple-vars

PostCSS plugin for Sass-like variables

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Option to enable nested variables

jednano opened this issue · comments

commented

As I understand it, this plugin sets global vars, but what if I wanted to limit the scope of vars to the container in which they were defined and only up the stack from there? I'm imagining an option like scoped: true that would work like so:

.foo {
    $background: white;
    background: $background;  /* white */

    $foreground: black;
    color: $foreground;  /* black */

    &--invert {
        background-color: $foreground;  /* black */
        color: $background;  /* white */
    }
}

.bar {
    color: $foreground;  /* Error: Undefined variable $foreground */
}

Let’s collect opinions. Anyway I have no free time until September 18.

@jonathantneal what do you think as owner of PreCSS?

commented

I would be more than happy to do the work. I'm just formalizing the issue here.

In one case I afraid for more complexity.

But in other your logic seems like more clear, because it is common variables behaviour.

  1. I like scoping the variables like JavaScript, with each {} creating closure, e.g. you can reference and modify ancestor variables, but new variables are scoped. This might be paired well with a !global flag, similar to !default (not sure if you have that one either).
  2. PreCSS does not yet use postcss-simple-vars. I want to! It’s the inter-plugin talk that doesn’t let me.

In postcss-advanced-variables, the getter/setter does a lookup

@jonathantneal !global is too complicated (you know my vision of preprocessing). At least, JS developers live without it.

Maybe we should be closer to JS and looks where var was defined?

$a: 1;
a {
  $a: 2;
  $b: 3;
}
// $a is 2, $b throws undefined error
commented

@ai the difference between JS and CSS here is that there is no var statement; thus, no way to differentiate between whether the user wants to change the value of the global var or define a new, local var. Consider the following JS:

var x = 5;
function foo() {
    var x = 7;
    return x;
}
foo(); // returns 7
x; // 5

Notice that the global var, x, is unchanged. Also, in CSS, there's no way to pass-in args with the same name, like JS does:

var x = 5;
function foo(x) {
    return x;
}
foo(7); // returns 7
x; // 5

Nonetheless, in both cases, JS preserves the value of the global var. As such, I think we would be more wise to assume every $x: [someValue] statement in CSS is a new var statement of sorts and NOT assume that the user wants to modify the global var unless they are in global scope. This could prevent some nasty bugs from happening in the future, where a new file is introduced that changes the global var, unintentially, and breaks other pages that relied on that global var to be constant.

This is the default behavior I'm requesting. If we want to allow people to modify global values inside nested container scopes, perhaps that should be a separate option. Personally, I would never enable that option, but others might.

commented

Also, it's much easier to implement if we just look in the current container and bubble up to find a value. If we do it the other way, it becomes much more complex.

@jedmao I thought about Ruby, Python and any other languages without var too.

commented

@ai are you confirming that Python works exactly the same as the JS examples I posted above? Because it does (just tested it). Not sure about Ruby though.

commented

Python example 1:

>>> x = 5
>>> def foo(x):
...     return x
...
>>> x
5
>>> foo(7)
7
>>> x
5

Python example 2:

>>> x = 5
>>> def foo():
...     x = 7
...     return x
...
>>> foo()
7
>>> x
5

But it do not work so in if and for?

commented

I don't understand how a CSS rule would at all be compared to a control statement (e.g., if and for). I see each container as more of a function scope.

Do you think it would make sense to introduce $root.foo: 7 or $global.foo: 7 in the case that the user intends to change the root value? It seems this would be easier for a user to specify than some sort of weird $local.foo variable.

This also ensures the most stable and reliable way is the default way and if you really want to modify the global var, you can do so explicitly.

commented

It seems the functionality I was looking for is too major a change and perhaps out of scope to this plugin; thus, I created a new plugin for this purpose, postcss-nested-vars.