I am using a component-based CSS style, so I have been using mixins to allow me to use media queries without accidentally compiling hundreds of them. This is what I am doing
(See comments above for context of this solution). I'd say that a price for non-repeating media queries will always be "repeating something else then". I.e. it either has to be the media depended property as in:
// ...................................
// usage:
.mq-default() {
.banner {
.background-image("test.jpg");
}
}
.mq-retina() {
.banner {
.background-image("test.jpg");
}
}
// ...................................
// impl:
.mq-default() {}
.mq-retina() {}
& {
.mq-default;
.background-image(@image) {
background-image: @image;
}
}
@media (min-device-pixel-ratio: 1.5) {
.mq-retina;
.background-image(@image) {
background-image: replace(@image, "\.", "_2x.");
background-size: 100%;
}
}
Or the media depended selector itself, as in:
// ...................................
// usage:
.background-image(banner, "test.jpg");
// ...................................
// impl:
.mq-retina() {}
@media (min-device-pixel-ratio: 1.5) {
.mq-retina;
}
.background-image(@class, @image) {
.@{class} {
background-image: @image;
}
.mq-retina() {
.@{class} {
background-image: replace(@image, "\.", "_2x.");
background-size: 100%;
}
}
}
P.S. For this simplified case it is also possible to modify the first example to get rid of repetitions, for example like this:
// ...................................
// usage:
.mq-common() {
.banner {
.background-image("test.jpg");
}
}
// ...................................
// impl:
.mq-default() {.mq-common}
.mq-retina() {.mq-common}
& {
.mq-default;
.background-image(@image) {
background-image: @image;
}
}
@media (min-device-pixel-ratio: 1.5) {
.mq-retina;
.background-image(@image) {
background-image: replace(@image, "\.", "_2x.");
background-size: 100%;
}
}
But that way it actually becomes a variant of the second example (where more complex code will lead to repeated selectors in the generated CSS because you won't want to put all properties into .mq-common
), not counting that the whole thing also turns to be quite head-scratching.
P.P.S. And at last, it is finally possible to consolidate "everything" (in the generated CSS) by introducing another level of indirection, but the source code itself becomes too verbose to be actually usable in practice. (In this example I'll break it into two files for a bit more clear code, but that's not really required - the imported file can be written as one big mixin):
// ...................................
// styles.less:
.banner {
.mq-default({
color: red;
});
.mq-medium({
color: green;
});
.mq-retina({
color: blue;
});
.background-image("test.jpg");
note: not "wrapped" properties will appear in every media block;
}
.background-image(@image) {
.mq-default({
background-image: @image;
});
.mq-retina({
background-image: replace(@image, "\.", "_2x.");
background-size: 100%;
});
}
// ...................................
// main.less:
.media-import(default);
@media (min-width: 600px) {
.media-import(medium);
}
@media (min-device-pixel-ratio: 1.5) {
.media-import(retina);
}
.media-import(@device) {
.mq-default(@styles) when (@device = default) {@styles();}
.mq-medium(@styles) when (@device = medium) {@styles();}
.mq-retina(@styles) when (@device = retina) {@styles();}
@import (multiple) "styles.less";
}