pistacchio
pistacchio

Reputation: 58863

Less: calculated value

I have the following piece of less:

@image-ui-wave-width: 28px;

[...]
.wave {
    &.saw {
        background-position: -@image-ui-tab-height * 2 -@image-ui-tab-height;
    }
    &.triangle {
        background-position: -@image-ui-tab-height * 3 -@image-ui-tab-height;
    }
}
[...]

Now, how can I add the rule that if any of those .wave elements also have the class .selected, the x value of background position must remain the same but the y value must be doubled?

Upvotes: 3

Views: 80

Answers (2)

Harry
Harry

Reputation: 89750

Option 1: (Has better browser support)

Less cannot pick up the value from a prior defined property and do any math operations on it. Due to this we have to manually calculate and assign the value to the property. Since you are already making use of variables, the code change should really be simple (given below):

@image-ui-wave-width: 28px;
@image-ui-tab-height: 28px;
.wave {
  &.saw {
    background-position: -@image-ui-tab-height * 2 -@image-ui-tab-height;
    &.selected{
      background-position: -@image-ui-tab-height * 2 -@image-ui-tab-height * 2;
    }
  }
  &.triangle {
    background-position: -@image-ui-tab-height * 3 -@image-ui-tab-height;
    &.selected{
      background-position: -@image-ui-tab-height * 3 -@image-ui-tab-height * 2;
    }        
  }
}

That could be compressed further by using loops and an @index variable (if the X value increases by the same factor for each item).

Below is an implementation of how that would work out. As you can see, all the 4 div elements have a gradient background image where the first 28px is taken by one color and the other 28px is taken by the rest.

For those without the selected class, the second color from the gradient gets displayed (because the Y position is -28px) and for those with the selected class, the first color from the gradient is displayed (because Y position is -56px and gradients by default get repeated).

.wave.saw {
  background-position: -56px -28px;
}
.wave.saw.selected {
  background-position: -56px -56px;
}
.wave.triangle {
  background-position: -84px -28px;
}
.wave.triangle.selected {
  background-position: -84px -56px;
}
.wave.saw {
  width: 56px;
  height: 28px;
  background-image: linear-gradient(to bottom, red 50%, green 50%);
  background-size: 56px 56px;
}
.wave.triangle {
  width: 56px;
  height: 28px;
  background-image: linear-gradient(to bottom, yellow 50%, orange 50%);
  background-size: 56px 56px;
}
div {
  margin-bottom: 20px;
}
<div class='wave saw'></div>

<div class='wave saw selected'></div>

<hr>

<div class='wave triangle'></div>

<div class='wave triangle selected'></div>


Option 2: (Poorer browser support - Browser Compatibility chart is available here)

Another thing that we could do now with the Level 4 Background and Borders Standard is to split the whole background-position into x and y parts so that the x position won't have to be repeated. This was originally removed from CSS3 spec but seems to be available now as mentioned here.

@image-ui-wave-width: 28px;
@image-ui-tab-height: 28px;

.wave {
    &.saw {
        background-position: -@image-ui-tab-height * 2 -@image-ui-tab-height;
        &.selected{
            background-position-y:  -@image-ui-tab-height * 2;
        }
    }
    &.triangle {
        background-position: -@image-ui-tab-height * 3 -@image-ui-tab-height;
        &.selected{
            background-position-y: -@image-ui-tab-height * 2;
        }        
    }
}

Below is the implementation for this approach where we override only the background-position-y value with a more specific selector:

.wave.saw {
  background-position: -56px -28px;
}
.wave.saw.selected {
  background-position-y: -56px;
}
.wave.triangle {
  background-position: -84px -28px;
}
.wave.triangle.selected {
  background-position-y: -56px;
}
.wave.saw {
  width: 56px;
  height: 28px;
  background-image: linear-gradient(to bottom, red 50%, green 50%);
  background-size: 56px 56px;
}
.wave.triangle {
  width: 56px;
  height: 28px;
  background-image: linear-gradient(to bottom, yellow 50%, orange 50%);
  background-size: 56px 56px;
}
div {
  margin-bottom: 20px;
}
<div class='wave saw'></div>

<div class='wave saw selected'></div>

<hr>

<div class='wave triangle'></div>

<div class='wave triangle selected'></div>

Upvotes: 2

Persijn
Persijn

Reputation: 14990

Could this not be solved with adding another class (.selected) to the .wave selector?

.wave {
    [yourcode]
}
.wave.selected {
    &.saw {
        background-position: -@image-ui-tag-height * 2 -@image-ui-tab-height * 2;
    }
    &.triangle {
     background-position: -@image-ui-tab-height * 3 -@image-ui-tab-height * 2;
    }
}

Note
The .wave.selected must come after the .wave selector because the last one will override the css properties.

Upvotes: 2

Related Questions