I'm using LESS CSS 1.3.3. Sorry if this question has already been asked, I didn't find anything relevant on the web.
I have several class generators that look like this (example extremely simplified, just enough to trigger the error):
#genMarginTop (@name, @size) {
.@{name} { margin-top: @size; }
}
Then I use them to generate some actual classes:
#genMarginTop(mtStandard, 40px);
#genMarginTop(mtHalf, 20px);
So far, so good, LESS correctly generates those classes and I can use them in the HTML. However when I want to reuse such a generated class as a mixin somewhere else, I get an error:
.someClass {
.mtStandard; // won't work, see error below
// more stuff
}
The error I get is:
NameError: .mtStandard is undefined in /.../example.less:161:4
160 .someClass {
161 .mtStandard;
162 // more stuff
Of course I try to use the mixin after the class has been generated. It looks like LESS somehow won't register such generated classes internally after it generates them, but I could well be wrong.
Is there a way to reuse such generated classes as mixins in other classes? Being quite new with LESS, and their documentation being rather sparse about generated classes, I'm at a total loss (especially since this is the only syntax that seems to be accepted for mixins).
Thanks for reading me.
Note: The reason why I use such class generators is because they are much more complex than the example above (think nested classes that all depend on a common set of parameters), and I'm embedding the generated classes in various @media
queries to support any device type in a "Zen" fashion. In the end I get something like:
@media (max-width: 1024px) {
#genSomething(something, somethingParam1, ...);
#genSomething(somethingElse, somethingElseParam1, ...);
#genStuff(stuff, stuffParam1, ...);
}
@media (max-width: 240px) {
#genSomething(something, somethingParam2, ...);
#genSomething(somethingElse, somethingElseParam2, ...);
#genStuff(stuff, stuffParam2, ...);
}
// etc
Here's a test case for @MartinTurjak 's solution, I can confirm that this works as expected, nested classes and everything:
.explicit {
margin-top: 1;
input { margin-top: 1; }
}
.reuseExplicit {
.explicit;
margin-bottom: 1;
}
#generator (@arg) {
margin-top: @arg;
input {
margin-top: @arg;
}
}
.generated { #generator(1); }
.reuseGenerated {
.generated;
margin-bottom: 1;
}
Which correctly generates: (notice how explicit/generated yield the very same result)
.explicit {
margin-top: 1;
}
.explicit input {
margin-top: 1;
}
.reuseExplicit {
margin-top: 1;
margin-bottom: 1;
}
.reuseExplicit input {
margin-top: 1;
}
.generated {
margin-top: 1;
}
.generated input {
margin-top: 1;
}
.reuseGenerated {
margin-top: 1;
margin-bottom: 1;
}
.reuseGenerated input {
margin-top: 1;
}
Unfortunately. The selector interpolation is just string interpolation, and the string gets then printed into css, so no class object is generated in the less run.
So you can design a generator/mixin, that includes your operation:
#genMarginTop (@size) {
margin-top: @size;
}
But then build classes by calling the mixins / generators:
.mtStandard {#genMarginTop(40px);}
.mtHalf {#genMarginTop(20px);}
And this way they are class objects that you can use for mixin =)
.someClass {
background-color: #FFF;
.mtStandard;
//more of this stuff
}
This looks a bit silly in this simple example, but maybe something like this:
#bggenerator (@color) {
background-color: @color;
}
#bggenerator (@color, dark) {
@blend : @color + #842210;
background-color: darken(@blend, 30%);
}
#bggenerator (@color, @url, @rest) {
background: "@{color} url('@{url}') @{rest}";
}
.mtStandard {
#genMarginTop(40px);
}
.someClass {
.mtStandard;
#bggenerator(#FFF, "bgimage.png", left top no-repeat);
//more of this stuff
}
Or something that does even more exciting stuff with the arguments
The .@{name}
syntax will now work just as the original question had desired.
I came up with a work around for this while working on another question, so I'm posting it as a second answer, since it goes in a totally different direction than my earlier answer.
This solution requires a couple of steps (so is not as convenient as a final fix in LESS would be), but would give actual functionality of being able to use dynamically generated class names .
First: Define your dynamic classes
This is just as you planned.
#genMarginTop (@name, @size) {
.@{name} { margin-top: @size; }
}
#genMarginTop(mtStandard, 40px);
#genMarginTop(mtHalf, 20px);
Second: Compile that file into CSS
So lets say you compile your dynamicClasses.less
into dynamicClasses.css
. This causes the dynamic class names to "resolve" to actual classes.
Third: Import that CSS as LESS into a 2 nd LESS file that uses the dynamic class names
Using type casting for @import
, we do this:
@import (less) dynamicClasses.css;
This takes those resolved class names in the dynamicClasses.css
file and imports them as LESS , which makes all the class names now available as mixins. So you can do as you desired:
.someClass {
.mtStandard; // will work
// more stuff
}
I agree. It looks like LESS does not register those classes for mixin purposes.
This LESS code:
#genMarginTop (@name, @size) {
@genMarginTopNameCheck: @name;
.get(@name) when (@name = @genMarginTopNameCheck) { margin-top: @size; }
.@{name} { .get(@name); }
}
#genMarginBot (@name, @size) {
@genMarginBotNameCheck: @name;
.get(@name) when (@name = @genMarginBotNameCheck) { margin-bottom: @size; }
.@{name} { .get(@name); }
}
#genMarginTop(mtStandard, 40px);
#genMarginBot(mbStandard, 20px);
#genMarginTop(mtSpecial, 80px);
.myClass {
.get(mtStandard);
.get(mbStandard);
}
.myClass2 {
.get(mtSpecial);
.get(mbStandard);
}
Generates this CSS
.mtStandard {
margin-top: 40px;
}
.mbStandard {
margin-bottom: 20px;
}
.mtSpecial {
margin-top: 80px;
}
.myClass {
/* NOTE the mtStandard definition is missing here !!! */
margin-bottom: 20px;
}
.myClass2 {
margin-top: 80px;
margin-bottom: 20px;
}
Each mixin is defining a guarded .get()
mixin based off the @name
to get the styles, and that is cross checked to a unique NameCheck
variable name for that mixin. All your actual code is defined in the .get()
, and that mixin is used to actually generate the .@{name}
class code.
This works fine every time for generating the actual class name. However, the getter function at present is only working for the class name last defined by a use of the mixin. So as you can see above, my get call for mtStandard
is not working because my setting of mtSpecial
has apparently overwritten the #genMarginTop
.get()
mixin with the mtSpecial
definition.
Now I assume you are going to want to call #getMarginTop
and your other such mixins more than once, so obviously this is still an incomplete solution . I've figured out how you can get the class generated by the top level mixin to be used as a 'mixin' for another class using the .get()
, but I haven't figure out how to make the .get()
not get overridden when the top level mixin is called again.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.