3

I have a small question... Is there any option to mix multiple background with LESS?

I have this setup for background in LESS:

.background_centered(
  @url,
  @position_horizontal: center,
  @position_vertical: top,
  @background-repeat: no-repeat,
  @transparency: transparent) {
    background: @arguments;
}

now: i need to write in out put style with multiple background, so i do this:

.class {
   .background_centered(url('../img/war_top_baner_gp.png'),url('../img/war_header_bg.png'));
}

something is not right bc in final output i have this:

background: url('/../img/war_top_baner_gp.png') 
            url('/../img/war_header_bg.png') top no-repeat transparent;

what is wrong? Whether or not it is possible to do so?

Cody Guldner
  • 2,888
  • 1
  • 25
  • 36
Lukas
  • 7,384
  • 20
  • 72
  • 127
  • You're actually sending `url('/../img/war_header_bg.png')` as the value for `@position_horizontal`. As a Sass user, I would typically add parentheses to remove ambiguity: `@include background_centered((url('../img/war_top_baner_gp.png'),url('../img/war_header_bg.png')));`. I'm not sure what the work around would be for LESS. – cimmanon Mar 14 '13 at 15:29
  • i try with that and i have syntax error :( – Lukas Mar 14 '13 at 15:32
  • see my answer, which uses straightforward LESS syntax for solving that – Michał Rybak Oct 11 '13 at 08:16

4 Answers4

10

I am not aware of less natively having a functionality of applying/looping through all arguments of a mixin, but there is a lot of options how to overcome this.

You can add a custom javascript function to the less block that does what you want. Here is a link to a nice reference for custom functions.

But you can also just build a little loop in less:

    // for loop
    .for(@l,@obg,@i:1) when (@l > @i) {
      @nbg: `@{url}[@{i}]`;
      @bg: ~"@{obg}, @{nbg} @{rest}";
      .for(@l, @bg, @i + 1);
    }

    // multiple background urls + additional bg properties
    .bgmixin(@url, @rest){
      @num: unit(`@{url}.length`);
      @bg: ~`@{url}[0]` @rest;
      .for(@num, @bg);
      background: ~"@{bg}";
    }

    // defining bg urls
    @url: 'url("../img/war_top_baner_gp.png")', 'url("../img/war_header_b‌g.png")';

    // including the bgmixin in .class
    .class{
      .bgmixin(@url, center top no-repeat transparent);
    }

And the output is

    .class {
          background: url("../img/war_top_baner_gp.png") center top no-repeat transparent,
                      url("../img/war_header_b‌g.png") center top no-repeat transparent;
    }

If I understood you right this is what you wanted.


Edit: I just wanted to add here that my idea here was to find a more general solution that is actually looping/recursing through array elements, which makes it easy to use different attributes with their respective images - so you feed the function an array of urls and an array of the other attributes. Here I'll try to illustrate the idea:

    .for(@l,@obg,@i:1) when (@l > @i) {
      @nbg: `@{url}[@{i}]`; @nattr: `@{attr}[@{i}]`;;
      @bg: "@{obg}, @{nbg} @{nattr}";
      .for(@l, @bg, @i + 1);
    }

    .bgmixin(@url, @attr){
      @num: unit(`@{url}.length`);
      @bg: ~`@{url}[0]` ~`@{attr}[0]`;
      .for(@num, @bg);
      background: ~"@{bg}";
    }

    @urls: "url('../img/centered_image_bg.png')", "url('../img/left_image_bg.png')";
    @attr: "center top no-repeat transparent", "left top y-repeat";

    .class{
      .bgmixin(@urls, @attr);
    }

and the output will look like this:

    .class {
        background: url('../img/centered_image_bg.png') center top no-repeat transparent,
                    url('../img/left_image_bg.png') left top y-repeat;
    }
Martin Turjak
  • 20,896
  • 5
  • 56
  • 76
  • 1
    thx for help, but i think that solution from @ScottS is a bit simpler – Lukas Mar 15 '13 at 09:39
  • 2
    That is nice that your solution does allow for attributes to be set for each one differently. While that was probably not the OP's need with his mixin titled `background-centered`, it is a valuable contribution to getting a general solution for others. +1. – ScottS Mar 15 '13 at 11:38
5

It is challenging in LESS to pass multiple property values to a single property. YOur current code obviously works well for single backgrounds. To get multiple, you have to usually work with strings.

The following allows multiple urls to be input by passing them as a single string to the first parameter, and then uses inline javascript to do a replacement on the string and concatenate those urls to the other parameters.

LESS

.background_centered(
  @urls,   
  @position_horizontal: center,
  @position_vertical: top,
  @background-repeat: no-repeat,
  @transparency: transparent ) {

  @combinedValues: ~"@{position_horizontal} @{position_vertical} @{background-repeat} @{transparency}";
  @urlsRewrite: ~`@{urls}.replace(/\)/g, ') @{combinedValues}')`;
  background: @urlsRewrite;
}

.class {
   .background_centered("url('../img/war_top_baner_gp.png'), url('../img/war_header_bg.png')");
}

Output

.class {
  background: url('../img/war_top_baner_gp.png') center top no-repeat transparent, url('../img/war_header_bg.png') center top no-repeat transparent;
}
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • smooth ... I got a bit too excited with applying the thing to an array that I didn't even think of putting in a single string, hehe =) – Martin Turjak Mar 14 '13 at 19:39
  • ok, i guess this is more flexible and simple solve than this above, so it's work perfectly, much thx, this was harsh, BR – Lukas Mar 15 '13 at 08:26
  • @djlukas777: Yes, my answer is simpler for your case given. Martin's is more general and flexible, should you ever need the ability to apply different settings to the background images. – ScottS Mar 15 '13 at 11:40
1

To pass a list of comma-separated arguments to a mixin, just use ; instead of comma in mixin call:

 .mixin(@bg, @color) {
   background: @bg;
   color: @color;
 }

 .class {
   .mixin(url('img/bg.png') no-repeat, red; white);
 }

outputs:

.class {
  background: url('img/bg.png') no-repeat, #ff0000;
  color: #ffffff;
}
Michał Rybak
  • 8,648
  • 3
  • 42
  • 54
0

You don't need in mixin to glue several backgrounds. You can use native merge function of LESS language.

The merge feature allows for aggregating values from multiple properties into a comma or space separated list under a single property. merge is useful for properties such as background and transform.

So, your less code may look like:

.element {
  background+: url("../1.png") center top no-repeat transparent;
  background+: url("../2.png") left top repeat;
  background+: url("../3.png") right top repeat;
}

This is much simpler than complex mixins.

Generated css:

.element {
  background: url("../1.png") center top no-repeat transparent,
              url("../2.png") left top repeat, 
              url("../3.png") right top repeat;
}
3rdthemagical
  • 5,271
  • 18
  • 36