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

2019-02-20 02:59发布

问题:

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?

回答1:

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


回答2:

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');
}


标签: less