Search code examples
csslessmixins

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


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

Solution / test case

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

Solution

  • 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