Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properties, maps and each. Trying to generate CSS custom properties #3368

Closed
lostkeys opened this issue Feb 22, 2019 · 6 comments
Closed

Properties, maps and each. Trying to generate CSS custom properties #3368

lostkeys opened this issue Feb 22, 2019 · 6 comments

Comments

@lostkeys
Copy link

So I'm trying to combine the power of preprocessing with the versatility of CSS Custom Properties. The use case is a theming tool where Less is used to generate the base styles and user tweaks can be handled in the browser.

@vars: {
  background-color: black;
  color: contrast($background-color, #000, #fff);
}
  
:root {
  each(@vars, {
    --@{key}: @value;
  });
}

div {
  display: inline-block;
  padding: 1rem;
  background-color: var(--background-color);
  color: var(--color);
}

However this example breaks with the each loop returning the following error error evaluating function each: Property '$background-color' is undefined. I kind of understand why this is happening though. Do someone know of a different way to solve this?

Here is a Codepen demo

@seven-phases-max
Copy link
Member

seven-phases-max commented Feb 22, 2019

A simplest workaround would be to use a mixin instead of a DR to define the map, e.g.:

.vars() {
    b: black;
    c: contrast($b);
}
  
:root {
    each(.vars(), {
        --@{key}: @value;
    });
}

(you can define both if @vars is required for something else):

@vars: {.vars}

I kind of understand why this is happening though

Yes, I guess it's pretty obvious - though I still would count this as a bug (not sure if there's already a corresponding ticket, but looks like [] accessors should evaluate rulesets before returning a value from within).

P.S. Alternatively you can turn the DR<->mixin conversion upside-down and hide it within :root:

@vars: {
    b: black;
    c: contrast($b);
}


:root {
    .-() {@vars()}
    each(.-(), {
        --@{key}: @value;
    });
}

@matthew-dean
Copy link
Member

but looks like [] accessors should evaluate rulesets before returning a value from within

I don't think we ever discussed this as a direct requirement. Are there any possible side-effects of doing this? As in, if that change were made, could that break any code relying on current each() behavior?

@seven-phases-max
Copy link
Member

seven-phases-max commented Feb 22, 2019

I don't think we ever discussed this as a direct requirement.

Well, yes, in that sense it's more a like a feature request then (I was just assuming that w/o this change, it would make more sense to advertise mixins as a primary method to define maps ;)

As in, if that change were made, could that break any code relying on current each() behavior?

I suppose it will change the behavior of code like:

@vars: {
    b: black;
    c: $b;
}

div {
    result: @vars[c]; // -> white  
    b: white;
}

(i.e. the issue is not each specific). But I guess such code is too strange to exist.

@lostkeys
Copy link
Author

Awesome, Thanks! Is there any reason not to use a mixin instead of a map?

@seven-phases-max
Copy link
Member

seven-phases-max commented Feb 22, 2019

Is there any reason not to use a mixin instead of a map?

First of all, strictly speaking it's confusing to word it like "mixin instead of a map". "Map" (as well as "namespace") is a logical concept. Rulesets, mixins and "detached-rulesets" become a map only when you throw the [] operator (or a function like each) at them.

To be honest I started to test the feature only yesterday, so I don't have enough data.
But theoretically, all these variations of maps (in no particular order: variable[property], variable[variable], ruleset[variable], mixin[property], mixin[variable]) should go less or more the same in basic use, so when it comes to typical use-cases (like above, i.e. not involving some complex code inside of {}), essentially it's just the visual appearance (all these @, ., (), #) to drive a decision on which one to use.

The 6th variation of map: ruleset[property] is obviously unique (so I did not count it above) because unlike others it (by being a regular CSS ruleset) will appear in the output by default.

@matthew-dean
Copy link
Member

I'm not sure why args were not being evaluated anyway, which they should be for functions-- wait, maybe it's because root functions don't have args evaluated? Or is it that root functions aren't evaluated after other rules? 🤔

In any case, this fixes it, but it's worth a review. #3546

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants