LESS CSS retina media queries without redundancy

懵懂的女人 提交于 2019-12-18 09:47:43

问题


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 for screen sizes:

Main file:

.mq-medium() {}

@import //other files

@media only screen and (min-width: 600px) {
  .mq-medium;
}

Another file:

.mq-medium() {
  .banner {
    width: 50%;
  }
}

This can be used several times and results in grouped queries.

The Problem

I am trying to do the same thing for retina background-image queries, and am having trouble figuring out how to do so. This is my test:

.mq-retina() { }

.background-image(@image){
  @filename:  ~`/(.*)\.(jpg|jpeg|png|gif)/.exec(@{image})[1]`;
  @extension: ~`/(.*)\.(jpg|jpeg|png|gif)/.exec(@{image})[2]`;
  background-image: ~`"url(@{filename}.@{extension})"`;
  .mq-retina() {
    & {
      background-image: ~`"url(@{filename}_2x.@{extension})"`;
      background-size: 100%;
    }
  }
}

.lol {
  .background-image("test.jpg");
}

@media only screen and (min-device-pixel-ratio: 1.5) { //shortened for this example
  .mq-retina;
}

But the output is just

.lol {
  background-image: url(test.jpg);
}

I believe this has to do with scoping issues, but am unsure how to resolve this. How can I add to the .mq-retina() mixin without scoping problems?


回答1:


(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";
}


来源:https://stackoverflow.com/questions/26000660/less-css-retina-media-queries-without-redundancy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!