csslessless-mixins

LESS: How can I pass a mixin as an argument to another mixin?


I have some basic mixins that apply some rules using media queries

.on-small(@rules) {
  @media (@minWidthSmall) { @rules(); }
}

.on-medium(@rules) {
  @media (@minWidthMedium) { @rules(); }
}

// and .on-large, .on-x-large and so on

And I'm trying to build a very simple flex-based grid system, I'm trying to pass the mentioned mixins as parameters so I can have a generic .make-column mixin. as follows:

.make-col(@break-point-mixin, @span, @size) {
  flex: 1;
  box-sizing: border-box;


  /***********************************************************
  Is the following line possible in LESS somehow?
  ***********************************************************/
  @break-point-mixin({
    width: percentage(@span/@size);
    min-width: percentage(@span/@size);
  });
}

.grid-col-on-small(@span: 1, @size: 1) {
  .make-col(@break-point-mixin: .on-small, @span, @size);
}

.grid-col-on-medium(@span: 1, @size: 1) {
  .make-col(@break-point-mixin: .on-medium, @span, @size);
}

But unfortunately passing @break-point-mixin as a parameter and calling it from inside .make-col crashes with:

Unrecognised input. Possibly missing opening '('


Solution

  • In this particular case (unlike a general case with an arbitrary mixin name) I'd say you're missing the fact that in .on-small/.on-medium these small and medium things are also nothing but parameters and thus should not be a part of the mixin names. With this in mind your example becomes:

    .on(small, @rules) {
      @media (@minWidthSmall) {@rules();}
    }
    
    .on(medium, @rules) {
      @media (@minWidthMedium) {@rules();}
    }
    
    .make-col(@device, @span, @size) {
      flex: 1;
      box-sizing: border-box;
      .on(@device, {
        width: percentage(@span/@size);
        min-width: percentage(@span/@size);
      });
    }
    
    // usage:
    
    .make-col(small, @span, @size);
    

    Same for your .grid-col-on-* mixins, they are just a single:

    .grid-col-on(@device, @span: 1, @size: 1) {
      .make-col(@device, @span, @size);
    }
    

    and so on.

    If you really want a flexible/generic grid - never hardcode device/breakpoint names into mixin or variable names (for more rationale and examples see https://github.com/less/less.js/issues/2702).