-
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
Use Dynamically Generated Classes as Mixins #1399
Comments
I would be happy for it to work.. BUT
less is meant to work no matter the order of the statements.. e.g. you can use a variable that is defined later in the current scope. that is why we do all the mixin calls before evaluating things that use variables.. but a selector uses variables.. so do the mixin calls twice and make sure we don't do the calls that have already been done? what if they change what the selector was? The solution I have suggested (I think in the bugs you reference) is that people have to use extend for dynamic selectors.. that doesn't suffer from the above because extend happens after selectors have been calculated.. The next problem with the extend solution (and also calling dynamic mixins) is that we don't parse dynamic selectors.. so we have no idea ".class" is a class.. worst case scenario we would have to take something like this
render it to
and then re-parse it into
BUT it would have to cope with selectors we don't recognise and also cope with someone who is purposefully trying to escape '&' because it is now some fancy css selector in 1 years time... Ok, in the first instance we could just re-parse classes that are simple If you have any suggestions to work-around these problems (or perhaps a comment from @SomMeri as they are good at this kind of things) then please go ahead |
@lukeapage: Thank you for the detailed explanation of the difficulties involved. I am a creative thinker, but by no means a master at programming, so whether I would be able to come up with a creative solution to the issues you state or not I don't know; but I will certainly meditate on them further. I don't entirely know how LESS works, but your explanation has shed some light on that. |
@LukePage Similar problem already exists in variable evaluation for mixins. Less solves it by making the order of the statements matter in special cases. Similar problem description: Each mixin call both returns variables into local scope and reads variables from caller scope. Next example defines two such mixins. Each of them creates one variable and uses variable defined in the other one. .mixin1() {
@in1: "in mixin1";
prop1: @in2;
}
.mixin2() {
@in2: "in mixin2";
prop2: @in1;
} I will call them from the same selector: #selector {
.mixin1();
.mixin2();
} What happens is that both
So, the order of statements does matter in this case. Full sample case: .mixin1() {
@in1: "in mixin1";
prop1: @in2;
}
.mixin2() {
@in2: "in mixin2";
prop2: @in1;
}
.outer {
@in1: "in outer";
@in2: "in outer";
#selector {
.mixin1();
.mixin2();
selector-prop1: "in mixin1";
selector-prop2: "in mixin2";
}
} Generated css: .outer #selector {
prop1: "in outer"; // mixin1 ignores variable defined in mixin2
prop2: "in mixin1";
selector-prop1: "in mixin1";
selector-prop2: "in mixin2"; // variable defined in mixin2 was returned
} The selector-scope problem @LukePage describes could work the same way as variable evaluation for mixins. E.g. the selector would use the same variable value as its body see (assuming it does not redefine it). It would ignore returned from calls after its definition. So this:
Would be equivalent to this: #outer {
@a: "a";
.mixin() {
@a: ".b";
}
.mixin();
.b() { // @{a} was originally here
prop: test;
@b: test;
}
.b();
.c {
prop: @b;
}
} And both would compile into following: #outer {
prop: test;
}
#outer .c {
prop: test;
} |
Another interesting question -should the following work? Sample input: @variable: ~".one, .two";
@{variable} {
declaration: value;
}
#caller {
.one();
} Similar case without variables work:
|
One consequence of my previous suggestion is that following would fail: .mixin() {
@variable: .value;
.value();
}
#space {
.mixin();
@{variable} {
size: 2;
}
} while very similar construction would work (most likely): #space {
@variable: .value;
.value();
@{variable} {
size: 2;
}
} Which is not good, I would expect those two to behave the same way. I will try to think about it more and collect various cases here. They may serve as test cases later on if we decide to do this. |
Yes, unfortunately there're a few scope visibility problems that make "interpolated mixins" matching to fail in certain cases. However as @SomMeri already mentioned those issues are not unique to "intepolation" feature. Another example for collection:
This one is very suprising (so simple and still fails?), but notice the following example with no interpolation:
Update: I made further investigation of the example above (the "interpolated" one): interesting, it can be fixed by forcing the variable evaluation right at the "searching for match" point (magically it does not even break the "lazy loading" stuff). But it's hard to predict what other side-effects such forced evaluation may bring in... For example the following code will create a sort of "ghost" mixin:
result:
|
+1
|
Btw.,
this is even yet another feature (something like this but with additional interpolation). |
@donaldpipowitch Sorry, I did not realize that it's not evident that this is partially supported since 1.6.0. For your example the syntax will be:
|
@seven-phases-max Thank you for the update. I noticed that this is possible, but I need to know that |
I guess so. So yep, it's more about #965 (combined with this one).
So usually it's helpful to mention some real-world use-cases instead of just minimal syntax usage. |
Say I use a library like Font Awesome (https://github.com/FortAwesome/Font-Awesome) which lets me choose the prefix for generated classes with |
See http://stackoverflow.com/questions/21178092 (mixins are not quite the best way to deal with the FA).
Well, have you seen any project that really changes the value of |
Lets say I'm the maintainer of "Awesome Library". My library creates classes, which should be used by a user. I prefix all my classes with |
What about using a namespace? |
You mean |
No, actual LESS namespaces. Go read about them on http://www.lesscss.org/ You can use the |
I know them, but they don't solve my problem or do I miss something? I don't want something encapsulated in Less, I want prefixed classes in my CSS output - without Less knowing the prefix beforehand. |
Ah, okay. Nevermind. I thought you were trying to replicate namespacing when a system for it already existed. |
This is a flawed approach. As a library writer you need to demarcate library's front-end and back-end (Imagine a JavaScript library maintainer saying "My library provides some functions that user can rename, now how can I use those renamed functions within my own library?"). In other words, despite the fact that preprocessors allow to use CSS classes as mixins (which is a nice syntax sugar bonus for the end-users), a library writer should avoid re-using its front-end entities as its own back-end entities (at least when those front-end entities are meant to be modified by user). E.g.:
Do:
Regardless of all those features supported or not supported by Less, this is just the rule#1 to keep a library maintenance easier and future-proof. So yet again not denying importance of #1399/#965 combo I would say it's not a good idea for a library to rely on those features (as a prefix/namespace resolver for a mixin) even when/if they are implemented. OK, I think the main idea is clear: if you need to use/provide mixins then do use/provide mixins (parametric). (Yes, these mixins won't be re-nameable just as variables like
Above I did put
No need to repeat |
Thank you for the insight! Very helpful. Maybe my idea was broken by design. I just try to find best practices for Less authoring. |
Sorry if this is the wrong place to ask this, but from what I can tell it does seem possible to mixin dynamically created classes in many cases, but not in others and I can't seem to get the mental model right. Why does this example compile:
...but this one doesn't:
|
Probably there's some bug in interpolated selector re-parsing not handling an empty value properly. Either way this: .foo {
.sm-p-1;
} is an awful idea (by now I guess this is Regardless of whether you generate these .foo {
.your-padding(sm, 1);
}
.your-padding(@device, @index) {
@value: ... // get the value of interest depending on the passed in parameters
padding: @value;
} See #3050, #2702 (comment), #1399 (comment), defining-mixins-quirk etc. for more details on why that |
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. |
This request is similar (though does not seem to be exactly the same) to the closed issues of #617 and #1133. It is also related to #1325 (both there and here seeks to "use" what Jon there calls "non-existent" classes, so the solving of one may solve the other). (If I missed a more exact statement of the same issue, forgive me for posting this new one.)
In all the issues use cases are sought, which I hope to provide here. The goal is to be able to essentially do the following (though it really becomes more powerful when in a loop structure):
Dynamically build a class name (which we can do now):
Then use that class name as a mixin (which currently gives a
.myName is undefined
error):Now as to reasons "why" to do it:
:extend
to extend dynamically generated classes? #1325. In such a case again, the expectation is that.span3
would just "work" like any other class that can be used as a mixin (though there, it was really desired to be more "extended").The key benefit is in those instances where loops are generating numerical differences not only in class names themselves, but properties within those classes. Being able to dynamically generate a number of classes based on whatever formula one wants, and then also being able to use those as a mixin would seem worthy of the effort to implement the feature. I hope this basic idea and the use cases here are enough to warrant a deeper look into this idea.
The text was updated successfully, but these errors were encountered: