没有冗余的CSS视网膜媒体查询

时间:2014-09-23 16:58:13

标签: css less media-queries

我使用的是基于组件的CSS样式,所以我一直在使用mixins来允许我使用媒体查询而不会意外地编译数百个。这就是我正在为屏幕尺寸做的事情:

主档案:

.mq-medium() {}

@import //other files

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

另一个档案:

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

这可以多次使用,并产生分组查询。

问题

我正在尝试为视网膜背景图像查询做同样的事情,并且无法弄清楚如何这样做。这是我的考验:

.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;
}

但输出只是

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

我认为这与范围问题有关,但我不确定如何解决这个问题。如何在没有范围问题的情况下添加.mq-retina() mixin?

1 个答案:

答案 0 :(得分:2)

(有关此解决方案的上下文,请参阅上面的评论)。 我会说非重复媒体查询的代价总是“重复其他东西”。即它必须是媒体依赖的属性,如:

// ...................................
// 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%;
    }
}

或媒体依赖选择器本身,如:

// ...................................
// 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。对于这种简化的情况,也可以修改第一个例子以消除重复,例如:

// ...................................
// 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%;
    }
}

但是这样它实际上变成了第二个例子的变体(更复杂的代码将导致生成的CSS中重复的选择器,因为你不想将所有属性都放入.mq-common),不计算整件事情也变成了令人头疼的事。

---

P.P.S。最后, 最终可以通过引入另一个间接层来整合“所有内容”(在生成的CSS中),但源代码本身变得过于冗长而无法在实践中实际使用。 (在这个例子中,我将它分成两个文件,以获得更清晰的代码,但这并不是真正需要的 - 导入的文件可以写成一个大混合):

// ...................................
// 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";
}