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 '('
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).
No, you can't send a mixin name as a parameter and use it in that way.
Instead you can do something like the below where the media query mixin is called directly from within the wrapper mixin instead of the .make-col
mixin. As the wrapper mixin is aware of the variables that the media query mixin needs this wouldn't result in any problems.
.grid-col-on-small(@span: 1, @size: 1) {
.make-col(@span, @size);
.on-small({
width: percentage(@span / @size);
min-width: percentage(@span / @size);
});
}
.grid-col-on-medium(@span: 1, @size: 1) {
.make-col(@span, @size);
.on-medium({
width: percentage(@span / @size);
min-width: percentage(@span / @size);
});
}
If you are concerned about rewriting the rules in the above mixins then you can set them to a ruleset like below and use it.
@colRules: {
width: percentage(@span / @size);
min-width: percentage(@span / @size);
};
.grid-col-on-small(@span: 1, @size: 1) {
.make-col(@span, @size);
.on-small(@colRules);
}
.grid-col-on-medium(@span: 1, @size: 1) {
.make-col(@span, @size);
.on-medium(@colRules);
}
Or, you can send the mixin name as a parameter and use guards like below. As we are dealing with break-points here and there shouldn't be lots of them, this approach should help and would probably get my vote.
@colRules: {
width: percentage(@span / @size);
min-width: percentage(@span / @size);
};
.make-col(@breakpoint, @span, @size) {
flex: 1;
box-sizing: border-box;
& when (@breakpoint = s) {
.on-small(@colRules); /* or you could replace this with that mixin's content also */
}
& when (@breakpoint = m) {
.on-medium(@colRules);
}
/* and so on for the rest */
}
.grid-col-on-small(@span: 1, @size: 1) {
.make-col(s, @span, @size);
}
.grid-col-on-medium(@span: 1, @size: 1) {
.make-col(m, @span, @size);
}