LESS CSS: Reuse generated .@{name} class as a mixin

混江龙づ霸主 提交于 2019-11-30 07:25:11
Martin Turjak

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

UPDATE LESS 1.7+ (Works as Desired)

The .@{name} syntax will now work just as the original question had desired.

LESS 1.4+ Workaround to Actually Use Dynamic Class Names

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 2nd 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.

Incomplete Solution

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;
}

Explanation and Disscussion of Final Issue to Resolve

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.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!