backwards mixin: a mixin defined many times and called once, rather than defined once and called many times
This is a demo of one way you could use mixins to put all your media query rules together under a single @media
statement. The merits of grouping media queries are dubious, but it's a good illustration of how to use backwards mixins.
In Less, when a mixin is called it will output the results of all mixins that match the pattern established by the call.
For example, the Less in Figure 1-1 compiles to the CSS in Figure 1-2.
// Less
.mixin (@switch; @color) {
display: block;
}
.mixin (opaque; @color) {
color: @color;
}
.mixin (faded; @color) {
color: fade(@color, 50);
}
.class {
.mixin(opaque; #acce55);
}
/* CSS */
.class {
display: block;
color: #5ad;
}
In other words, Less calls all matching mixins at the point of a mixin call.
It's this behavior that we exploit to group all media queries of a given type under one @media
block. This is demonstrated in 2.2-component.less & 2.3-media-queries.less. (The other files on the 2-level are just to show how this technique fits into a larger system.
There are significand downsides, however. For example, in this system you can't nest the media queries in a rule. If you're doing a lot of nesting (like in a multi-level .nav
, perhaps) you'd have to match all that nesting within the media query definition (see Figure 2).
But the major drawback is that you can't really use them inside other mixins, so complex libraries like Bootstrap (which uses mixin loops to generate its grid) wouldn't be able to use this.
// some-nav.less
.nav {
// rules
> li {
// rules
> a {
// rules
}
}
}
.in-stylesheet(async) {
.nav {
// async rules ...
> li {
// async rules ...
> a {
// async rules ...
}
}
}
}
I think this is probably the most useful use case. You use backwards mixins to extract print styles into their own file. See 3-print.less.
There are at least a few benefits to writing this way. Extrapolating from the print styles example, this could be used to extract styles not necessary for initial page load into a separate CSS file to be loaded asynchronously (see Figure 3); As you write your component's styles you can decide whether styles are necessary for page load.
// some-component.less
.some-component {
color: gray;
background-color: dodgerblue;
}
.in-stylesheet(async) {
.some-component {
transition: color .2s linear;
}
}
...
// async.less
@import (reference) 'some-component.less';
.in-stylesheet(async) {}
& {
.in-stylesheet(async);
}
I can't personally think of a use case for large-scale sites: There's almost no performance benefit to grouping media queries; Print styles aren't usually complex and can probably be extracted automatically with a post-processor, and there have historically been bugs with Less's @import (reference)
behavior when using :extend()
in the referenced file; And there are many tools for automating detection and extraction of asynchronous "below-the-fold" styles already out there.
Overall, though, I feel like the principle—using mixins "backwards" by creating many definitions and calling it once—is powerfull. In smaller-scale sites this technique could save some time and headaches.