-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Feature request: Property lookup (a.k.a Properties are Variables too) #2433
Comments
What is your use case? In current less.js, you can place foo value into variable and achieve something similar. This: .test {
@foo: 200;
foo: @foo;
bar: @foo / 2;
.child {
baz: @foo;
}
} compiles into: .test {
foo: 200;
bar: 100;
}
.test .child {
baz: 200;
} If you have a case where such refactoring is not possible, it would be helpful if you would posted it here. Generally speaking, less.js adds new features when some use case is impossible or too cumbersome to do. Use case would help us to decide how much is such feature needed (or we could find another way how to achieve what you wants). |
The usecase would be that you can build up semantic contexts, for example: @gutter-width: 30px;
.row {
margin-left: -(@gutter-width / 2);
margin-right: -(@gutter-width / 2);
.col-half {
width: 50%;
float: left;
padding-left: -$margin-left;
padding-right: -$margin-right;
}
} Since in bootstrap the margin is dependent on the padding and vice versa, why not connecting them directly rather than just using the same variable? You would delete multiple variable references and build up a more coherent module that relies on its context rather than just variables. The guys from Stylus obviously see a usecase for this otherwise they would have deprecated this as a relict. |
Another example would be alert boxes: .alert {
color: #f00;
background: lighten($color, 25%);
} |
I think it's not necessary but nice to have. Variables can do the job but direct property references are more readable. |
Of course it is not necessary, at all. We worked with variables for years and it's awesome. Especially the lazy loading behaviour every other Pre-Processor is lacking. Nonetheless I wanted to post this for consideration. |
I agree that something like this would be intuitive. A lot of times I have an initial value, set for a property, and if I want to use that value elsewhere, it has to be refactored into a variable and then re-added to the property. This proposal would be simpler for authors. There have been similar requests to have parts of the immediate Less tree accessible as structured data, so I'm for having more "accessors" to what you've already written. |
I see the concern to blow up the language too much so it might not be considered "sleek" anymore though. |
Reading #76 I found some similarities which might be combined, say if you That would really be useful and opens a whole new level of opportunities. |
@lukeapage What do you think the code impact would be? If local (current tree) properties could be shimmed to behave similar to local vars, it seems like it would be not that major (but you would know better). It could add a certain elegance to the language, since people could do:
Instead of:
The first example seems easier to read, and feels closer to the intention of the author. I personally have written code like the second example many times, so I like this idea. |
For local only lookups, i think the cost is small. Adding selectors might
lead to more parse complexity. Doesnt css columns use square brackets in
values?
|
No, not css columns, will have to think where i saw it.
|
Attribute values use square brackets, so if we're including selectors in the property lookup, then square brackets wouldn't work, because this is a valid selector:
The square brackets match an element that has the attribute "color". We could be more explicit, with something like prop().
However, I know in the past we've tried to avoid nested parentheses hell, so... what if we combine the
Something like that? That way attribute selectors are valid:
What do you guys think? |
I like |
Actually, if we thought of
...but I don't want to confuse things. Just an idea. |
For non-local lookups it's directly tied to #1848 (I guess the tricky part is only in crafting consistent syntax, internally in the tree variables and properties are handled almost identically so anything implemented for the first is quite easily extended to work with the second and vice-versa).
This way Btw., any ideas beside |
I was thinking about namespacing as I was mulling this over. Technically, this is different because we're (currently) talking about support for references in the local tree. We could forego selector lookups initially and, as you said, treat them like variables. If the property doesn't exist locally, go to the next parent block, and so on. We could, in fact, just pretend that properties are variables, albeit they need to be referenced in a different way. So, if we don't support referencing namespaced vars, then I think we wouldn't initially support namespaced properties. But we could support imported properties via mixin, since it would be the same as what variables do. In fact... don't we essentially do that already, since later properties will override previous ones? I would love to reference namespaced vars / properties as well. It would be amazing. And, like #1075, we may be close to a syntax that is flexible enough to point to any value anywhere in the AST. But we wouldn't have to implement it all at once. As far as special selectors, I know we've tried to avoid introducing extra symbols in these issues, but I feel like we've been jumping through hoops in #1075 and #1848 to not do so. For example, in #1848, at the end I mention this syntax:
But, of course, the extra
So, maybe we could kill two (possibly 3) birds with one stone and break up the tasks like this:
As far as alternatives to |
What about |
|
Er, nope. No idea what that is. |
It's a paragraph sign in (German) law |
Ah, right, I think I've seen that then. Regardless, it's not on the keyboard. |
Alright. As I figured out by fiddling around, |
Doh, I'm afraid I would vote for |
@seven-phases-max - Haha, I had the same visceral reaction the first time it was brought up, for the same reasons. However, I've become more pragmatic lately, and twisting existing symbols to mean more things (as we've been toying with in regards to And also, relative to your point, if we expand an existing symbol definition, we may back ourselves into a corner if we want to further expand the usage. |
That said, because this might be a new symbol / reference method, I think it's worth getting a lot of input / consensus for it. |
I understand that being able to do this: .rectangle {
width: 200px;
height: ${width} / 2;
} could be nice but this: .example {
color: lighten(${color, #mySpecialSelector}, 25%);
} is uselessly complex to read and manage. If someone would give me a piece of code like this to work on it would very tedious and complex to find out which is the actual color to be var el1 = document.createElement('div');
var el2 = document.createElement('div');
el1.className = document.querySelector('mySpecialSelector').id + '25percent';
el1.className = document.querySelector('mySpecialSelector').id + '10percent'; instead of: var CLASS_NAME = 'my-color-class';
var el1 = document.createElement('div');
var el2 = document.createElement('div');
el1.className = CLASS_NAME + '25percent';
el1.className = CLASS_NAME + '10percent'; I don't know if I gave the idea of what I mean. But I think all this thing is weird, at least for me and I wouldn't use it. Overall I think variables are a good and solid abstraction that already cover all this cases. Making the language more complex doesn't make it more powerful. And make it less readable doesn't help either. |
But I wrote exactly the same :) (Upd:. Err, I mean "I meant property lookup rules should be exactly the same as those of variables", (more over I know they already are the same within the compiler because it is the same code that handles variables and properties (with a few minor
is an exact quote from Variables > Lazy-Loading. Speaking of your example it's quite unhappy. Because the same example with variables steps into #1316 and the result is P.S. Strange thing: for the last three days it's four issues directly related to #1316 popped up (#2435, #2350, #2436 and now your example) Is it some kind of conspiracy? :) |
@seven-phases-max I misunderstood you and forgot about #1316. Sorry about both :). All those four issues are the same underlying problem? Is it easy/hard to fix in your opinion? I do not want to do major change in less.js yet (know too little about its scoping), but I am looking for something easy to medium hard to fix. |
Am I the only one who thinks that all this thing is unnecessary and makes the language more complicated and less readable? What is the exact benefit you're looking for? Definitely I agree with @SomMeri when he says
And I think his sample code #2433 (comment) no matter what it compiles to, it's too convoluted. |
Definition from Stylus:
So to capture the usecase I described earlier you could shorten definitions by saving variables, plus it is more concise since you connect the properties directly rather than over variables:
Just by reading The nesting-discussion and whether or not it should lookup all the parent selectors should be discussed elsewhere (#1848). |
Well, my involvement is only limited to hanging around and screaming if some proposed syntax/behaviour gets out of control :) Actually I'm neither for nor against it (I won't mind it because it was flying around from the earliest Less days (it was even (partially?) implemented in the initial Ruby version) and I know it should not burden compiler unless we start to invent insane syntactic constructions... Also I know that the fact a feature gets its "ReadyForImplementation" does not mean it actually to be implemented soon or ever... ;) |
Yes, it's the same underlying problem but in most cases it's more about different expectations of how these things should work (of how scoping should work and how it works actually) and not really the code that suffers from #1316 . We discussed possible ways to fix #1316 itself around #2212 (comment) (not so easy but probably possible) but those issues (half-issues/half-feature-requests) I mentioned (except your example above of course) are actually asking to fix it in opposite way or provide a backdoor for that (thus breaking current Less behaviour, the good example is #2435). @krnlde I'm sorry for mismentioning... |
I think you're probably misunderstanding. There's nothing proposed here that is a dynamic way to define variables. It actually seems like a very intuitive step for a few reasons. Variables in Less came directly from (or was inspired by) the behaviour of properties. In some preprocessors, if you assign a variable, then read it, then assign it, then read it, all within the same scope, you'll get a different result. In Less, the behavior is like CSS properties: the latest declaration in the scope wins. So, right now, variables and properties have a lot of overlap. If you call a mixin, you get not only its properties but its variables. And you can actually do things like add properties together (or rather, add its values) with the So, variables are meant to behave like properties, and properties have evolved to behave a lot like variables. In the end, you're assigning a value to a key. We have a way to reference the value for one type of key, and what's proposed here is simply a way to reference the value for the other type of key.
There wouldn't be any additional scoping rules to remember. These two blocks would become functionally equivalent as far as scoping. .block {
@height: 10px;
width: @height / 2;
}
.block {
height: 10px;
width: $height / 2;
} The difference is that height is output as a property in the second block. But scoping does not change. |
Or the TL;DR way to say it: properties in Less, by and large, already act like variables, but you cannot reference them. This feature would allow property referencing. Another way to demonstrate the above: //Less
.block {
@height: 10px;
width: @height / 2;
@height: 20px;
}
// output
.block {
width: 10px;
}
//Less w/ property reference
.block {
height: 10px;
width: $height / 2;
height: 20px;
}
//output
.block {
width: 10px;
height: 20px;
} |
@krnlde's example inspired another demo: .square(@width) {
height: @width;
}
@row: 100px;
.column-2 {
width: @row / 2;
.square($width);
}
.column-4 {
width: @row / 4;
.square($width);
}
// output
.column-2 {
width: 50px;
height: 50px;
}
.column-4 {
width: 25px;
height: 25px;
} |
This is a useful feature, in my case i needed to extend only some specific properties from another class (that class is defined in an external stylesheet so in order to use variables i would have to modify that stylesheet in each new version they publish) With this new syntaxis i could do it like this: The stylesheet.less provided from another source: .divheader{
height:50px;
color: red;
line-height: 1.5;
width: 100px;
} My stylesheet.less: .mydivheader{
.divheader.height; //invented syntax
.divheader.line-height; //invented syntax
color: black;
}
//output
.mydivheader{
height:50px; //inherited
line-height: 1.5; //inherited
color: black;
} So i only inherit the height and line-height properties of the divheader class... |
@ase69s In your case we would need to address referencing variables within rulesets. See #1848. Essentially, this feature would make property assignment behave (somewhat) like variable assignment (albeit with different referencing syntax), so your case wouldn't happen before #1848 is addressed. If / when implemented, I would see the syntax being a little closer to this: .divheader{
height: 50px;
color: red;
line-height: 1.5;
width: 100px;
}
.mydivheader {
height: ${.divheader > height};
line-height: ${.divheader > line-height};
color: black;
} However, since you're not calculating anything, there are a few other options available to you right now, such as: @divheader: {
height: 50px;
line-height: 1.5;
};
.divheader{
@divheader();
color: red;
width: 100px;
}
.mydivheader {
@divheader();
color: black;
} You could also have a mixin that sets properties, or use |
+1 I completely agree with Justineo: |
I'd say this is more than nice to have. I have a site that lets you build skins by picking a trim color that controls buttons, links, and misc elements. This is stored in a database, and gets bootstrapped onto the page via a As it stands now, I'll have to manually pick off-shade variants of the trim color and assign those to classes as well, but even then, I don't have very easy control over WHICH properties that faded trim color would get applied to (e.g. borders), inner backgrounds etc. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Note that simple property referencing ( |
For others who like me find this issue before the relevant docs: this was added to the documentation in 2018 https://lesscss.org/features/#variables-feature-properties-as-variables-new- |
I found a pretty neat feature in Stylus recently, a property lookup which allows you to use properties in the current or closest parent ancestor and use it for calculations.
In Stylus this would look like this:
which produces this CSS:
For less we could use the $-sign or maybe brackets to select properties. It then would look something similar to this:
or this respectively:
Thoughts on this?
The text was updated successfully, but these errors were encountered: