Search code examples
lessbackground-imagemixinsless-mixins

LESS: concatenate multiple background rules


I have a mixin that creates a gradient with vendors' prefixes, and I would like to add this background to a DIV in addition to another background-image.

.horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {
    background:@start-color;
    background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
    background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
    background-image+: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent);
    background-repeat: repeat-x;
  }

.foo
{
  background-image+:url('bg.png');
  .horizontal;
}

I thought the solution could be use of comma merging, that in my example I added only to standard CSS3 gradient declaration. Doing this, here the generated CSS:

.foo {
  background-image: url('bg.png'), linear-gradient(to right, #555555 0%, #333333 100%);
  background: #555555;
  background-image: -webkit-linear-gradient(left, #555555 0%, #333333 100%);
  background-image: -o-linear-gradient(left, #555555 0%, #333333 100%);
  background-repeat: repeat-x;
}

It's correct, but how to have this also for others vendors prefixes without losing flexibility of mixin? I tried to add + sign also on others "background-image: -webkit...." rules, but in this case, resulting CSS would be:

.foo {
  background-image: url('bg.png'), -webkit-linear-gradient(left, #555555 0%, #333333 100%), -o-linear-gradient(left, #555555 0%, #333333 100%), linear-gradient(to right, #555555 0%, #333333 100%);
  background: #555555;
  background-repeat: repeat-x;
}

...obviously not correct... any suggestion?


Solution

  • Using Less for generating vendor prefixes (or related items) is not the best way to do it. It is much better to use the libraries like Prefix Free or Auto Prefixer etc.

    Having said that, for your case I think using a separate parameter for the image would be the best option. The isurl() function returns true only if the input parameter is a URL.

    The default value for the @image parameter is set to none because this is not a URL and will take care of the blank/null value handling.

    .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%; @image: none) {
        background:@start-color;
        & when (isurl(@image)){
            background-image: @image, -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @image, -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @image, linear-gradient(to right, @start-color @start-percent, @end-color @end-percent);
        }
        & when not (isurl(@image)){
            background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent);        
        }
        background-repeat: repeat-x;
      }
    
    .foo{
      .horizontal(@image: url('bg.png'));
    }
    .foo2{
      .horizontal(@image: 'bg.png');
    }
    

    In the above mixin, based on whether the value for the @image variable is a URL or not, the appropriate output would be generated.


    In some cases, you may want to use a color (instead of/in addition to an image) in addition to the gradients and for that you can further enhance the mixin like below:

    .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%; @image: none; @color: none) {
        background:@start-color;
        & when (isurl(@image)) and not (iscolor(@color)){
            background-image: @image, -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @image, -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @image, linear-gradient(to right, @start-color @start-percent, @end-color @end-percent);
        }
        & when (iscolor(@color)) and not (isurl(@image)){
            background-image: @color, -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @color, -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @color, linear-gradient(to right, @start-color @start-percent, @end-color @end-percent);
        }
        & when (isurl(@image)) and (iscolor(@color)){
            background-image: @color, @image, -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @color, @image, -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: @color, @image, linear-gradient(to right, @start-color @start-percent, @end-color @end-percent);        
        }
        & when not (isurl(@image)) and not (iscolor(@color)){
            background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent);
            background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent);        
        }
        background-repeat: repeat-x;
      }
    
    .foo{
      .horizontal(@image: url('bg1.png'));
    }
    .foo2{
      .horizontal(@image: 'bg.png');
    }
    .foo3{
      .horizontal(@color: blue);
    }
    .foo3{
      .horizontal(@color: red; @image: url('abc.gif'));
    }
    

    Note: I have used background-image property in the above sample but if we want use a solid color along with gradients and/or image, then the background property should be used instead.