How do I make a list of CSS rules in LESS based on

2019-02-20 03:22发布

I'd like to make a LESS mixin for translating images like so:

.translate('/images/image.png', de, en-uk);

with an output that looks like this:

background-image: url('/images/image.png');
&:lang(de){ background-image: url('/images/image_de.png') }
&:lang(en-uk){ background-image: url('/images/image_en-uk.png') }

This would be easy if we were always translating the same number of languages, but unfortunately we are not (the content is the same across certain locales). I'm not sure how to make this number variable (which would future-proof the solution).

I guess what I'm looking for is a way to loop over each element in an array I pass and return another LESS rule for each.

Any ideas?

标签: less
2条回答
甜甜的少女心
2楼-- · 2019-02-20 03:45

This mixin uses target languages from a variable. It will loop through them and generate the code you want for each one:

.image-replace(@languages; @image-prefix) {
  @count: length(@languages);
  .loop(@count; @image-prefix);
  .loop(@count; @image-prefix) when (@count > 0) {
    .loop(@count - 1; @image-prefix);
    @lang: extract(@languages, @count);
    @image: %('%a_%a.png', @image-prefix, @lang);
    &:lang(@{lang}){
      background-image: url(@image);
    }
  }
}

To use it:

@languages: ~'de', ~'fr', ~'es', ~'ru', ~'en-UK', ~'pt-BR';
.section {
  .image-replace(@languages; ~'/images/image');
}

Result:

.section:lang(de) {
  background-image: url('/images/image_de.png');
}
.section:lang(fr) {
  background-image: url('/images/image_fr.png');
}
.section:lang(es) {
  background-image: url('/images/image_es.png');
}
.section:lang(ru) {
  background-image: url('/images/image_ru.png');
}
.section:lang(en-UK) {
  background-image: url('/images/image_en-UK.png');
}
查看更多
Ridiculous、
3楼-- · 2019-02-20 03:52

See Variadic mixin arguments, Loops, List Functions. For example it could be implemented somewhat like:

.test {
    .translate('/images/image.png', grc, lat, san);
}

.translate(@image, @langs...) {
    background-image: @image;
    .-(length(@langs));
    .-(@i) when (@i > 0) {
        .-((@i - 1));
        @lang: extract(@langs, @i);
        &:lang(@{lang}) {
            background-image: replace(@image, "\.", "_@{lang}.");
        }
    }
}

replace function requires Less 1.7.0 but for earlier versions you can use plain string interpolation/concatenation or format function as in @helderdarocha answer.

(Also note that the @langs... mixin parameter above can also accept the language list as a single variable), e.g.:

@languages: de, fr, es, ru, en-uk; // in fact commas here are optional too 

.test {
    .translate('/images/image.png', @languages);
}

And just in case, the same mixin using for wrapper (just to show that Less loops don't have to be that scary :):

@import "for";

.translate(@image, @langs...) {
    background-image: @image;
    .for(@langs); .-each(@lang) {
        &:lang(@{lang}) {
            background-image: replace(@image, "\.", "_@{lang}.");
        }
    }
}
查看更多
登录 后发表回答