问题
I'm trying to create a Less mixin to generate media queries. The goal is to store my breakpoints in a variables.less
file, and loop through them to create @media
blocks.
The mixin would then be used as:
.mq-medium({
// rules
});
and generate CSS like:
@media only screen and (min-width: 640px) {
// rules
}
Here's my current mixin:
variables.less
/* media queries */
@breakpoints: small 0, medium 640px, large 1024px, xlarge 1281px, xxlarge 1440px;
mediaqueries.less
.createMQClasses(@iterator:1) when(@iterator <= length(@breakpoints)-1) {
@breakpoint: extract(extract(@breakpoints, @iterator),1);
@breakpoint-next: extract(@breakpoints, (@iterator + 1));
@breakpoint-next-px: extract(@breakpoint-next, 2);
.mq-@{breakpoint} {
@media only screen and (min-width: extract(extract(@breakpoints, @iterator),2)) {
}
}
.createMQClasses((@iterator + 1));
}
.createMQClasses();
So far my code loops through and generates empty @media
blocks. However, I need to pass any @rules
through to the output. I've done this with static classnames previously, like this:
.mq-medium(@rules) {
@media only screen and (min-width: extract(extract(@breakpoints, 2),2)) {
@rules();
}
}
And that works fine.
But with the dynamic name it's causing errors. I've tried adding an additional parameter to the .mq-@{breakpoint}
statements, like:
.mq-@{breakpoint}(@rules) {
@media only screen and (min-width: extract(extract(@breakpoints, @iterator),2)) {
@rules();
}
}
This results in various errors. How can pass the included rules through so they're included in the mixin's output?
回答1:
No, you can't use variables in parametric mixin names. Thus you can't "generate" mixins by a list of identifiers. So you need to invent some other approach...
Well, there're several possibilities - for example notice that @{breakpoint}
part of the mixin name is nothing but just another mixin parameter. Then it could be coded as something like (simplified):
// usage:
@devices: small 0, medium 640px, large 1024px;
.mq(medium, {
foo {
bar: baz;
}
});
// impl.:
.mq(@id, @style) {
.-(length(@devices));
.-(@i) when (@i > 0) {
.-(@i - 1);
.--(extract(@devices, @i));
}
.--(@device) when (@id = extract(@device, 1)) {
@media (min-width: extract(@device, 2)) {@style();}
}
}
---
Alternatively (just to illustrate those "several possibilities"), it is actually possible to make the device id to be a prefix part of the name via certain tricks&hacks. E.g.:
// impl.:
// (here mixin definitions should always go before their usage)
.make-media-mixins();
.make-media-mixins(@i: length(@devices)) when (@i > 0) {
.make-media-mixins(@i - 1);
@device: extract(@devices, @i);
@id: extract(@device, 1);
.@{id} {.mq(@rules) {
@media (min-width: extract(@device, 2)) {@rules();}
}}
}
// usage:
@devices: small 0, medium 640px, large 1024px;
.medium.mq({
foo {
bar: baz;
}
});
This trick abuses the fact that variables can be used as part of a ruleset name (and then we can use it as a non-parametric namespace prefix), but I would never recommend this code for a real project (it's just too hacky and flawed by any means).
来源:https://stackoverflow.com/questions/34643549/dynamic-classnames-with-parameters-in-less-mixin