9

H i,

Hoping you can help.

Is there a way for LESS to return just a value - feel like I'm missing something very obvious

Say I have:

@unit:em;
@basevalue:1;

Can I use something to give me a shorthand return for -

.someClass {  padding: ~'@{basevalue}@{unit}'; }

Like say:

.returnUnit() { ~'@{basevalue}@{unit}'; }

.someClass {  padding: returnUnit(); }

because what I'm ultimately hoping for is:

.returnUnit(@val) { @basevalue*@val@{unit}; }
.someClass {  padding:returnUnit(0.5); }

Using a mixing I have to define the style property, however the value of this return function would be used for many different css properties.


Hope I made sense and I am just lacking deeper rtfm.

Many Thanks if you can.


Update as @Chococrocs pointer to the docs, thanks.

.average(@x, @y) {
  @average: ((@x + @y) / 2);
}

div {
  .average(16px, 50px); // "call" the mixin
  padding: @average;    // use its "return" value
}
  • Looks like what I need ? - just seeing if I can always tag on the unit variable to it....

Update: That gets part way ...

.unitRelative(@val) {
  @value : @basevalue*@val;
  @relative: ~'@{value}@{unit}';
}
/* usage */

 .someClass { 
  .unitRelative(2);
  padding: @relative;
}

But not when

.someClass {
    .unitRelative(2);
    padding:@relative;
    .unitRelative(3);
    margin:@relative;
}

Is there another way ?

4
  • I'm not sure if it's possible to separate @unit and @basevalue in LESS. Does it hurt your design to combine them into a single variable? It doesn't seem like you'd lose much by doing that, since any time you change one, you'd need to change the other as well. Commented Apr 1, 2014 at 18:50
  • Thanks @recursive. You could be right, can I still multiple say like - 10em * 6 ? - Ive just added an edit too with what looks like the right lines - just trying that now Commented Apr 1, 2014 at 18:56
  • I have been combining them like `padding:~'@{baseval}@{unit}'; but it would be neater to be more Dry Commented Apr 1, 2014 at 18:58
  • 1
    Personally I would suggest one of these two methods (the rest looks extremely bloating for me). Commented Mar 25, 2015 at 11:30

6 Answers 6

13

LESS has no way as of yet to create a true "function," so we cope with it.

First

You can just use the unit function, like so:

LESS

.someClass {  padding: unit(@basevalue, @unit); }
.someOtherClass {  padding: unit(@basevalue*0.5, @unit); }

CSS

.someClass {
  padding: 1em;
}
.someOtherClass {
  padding: 0.5em;
}

Second

The mixins as functions is okay in some situations, but as you discovered, has the limitation of only setting the value once on the first call (and that is assuming a variable of the same name does not exist in that scope already).

LESS (first works right, second doesn't)

.returnUnit(@val:1) { 
    @return: unit(@basevalue*@val, @unit); 
}

.someThirdClass { 
  .returnUnit(0.4); 
  padding: @return;
 }
.someOoopsClass { 
  .returnUnit(0.4); 
  padding: @return; 
  .returnUnit(0.3); 
  margin: @return;
}

CSS Output

.someThirdClass {
  padding: 0.4em;
}
.someOoopsClass {
  padding: 0.4em;
  margin: 0.4em; /* Ooops! Not 0.3em! */
}

Third

Limitation of the Second idea can be avoided by a second wrapping, as it isolates the scope for each variable returned by .returnUnit(), like so:

LESS

.someAccurateClass { 
    & {
        .returnUnit(0.4); 
        padding: @return;
    } 
    & { 
        .returnUnit(0.3); 
        margin: @return;
    }
}

CSS Output

.someAccurateClass {
  padding: 0.4em;
  margin: 0.3em; /* Yes! */
}

Fourth

It may be better to merge ideas from the First and Third by adding some global variables and doing this:

LESS

@unit:em;
@basevalue:1;
@val: 1;
@setUnit: unit(@basevalue*@val, @unit);

.someAwesomeClass { 
    & {
        @val: .2; 
        padding: @setUnit;
    } 
    & {
        @val: .1; 
        margin: @setUnit;
    }
}

CSS Output

.someAwesomeClass {
  padding: 0.2em;
  margin: 0.1em;
}

So here we are using the unit function still as the First idea, but have assigned it to the variable @setUnit, so each time the variable is called, it runs the function. We still isolate our property blocks using the & {} syntax like in the Third solution, but now we just set the @val to what we want and call the @setUnit where we want.

Sign up to request clarification or add additional context in comments.

2 Comments

that fourth one is ace! Sweet, thanks for the in depth explanation, just what I was looking for. Nice use of the @val scoping it up like that. It bends my head how Less uses variables this way :) thanks.
Goddammit, because of that i just lost over 1 hour at work -.- They really should but the information about "unit" to the polarising section. Even better, they should it add to their feature list first!
6

There is a hack that is mentioned here by fabienevain using a global js function. Seems to be good option if you want a function with actual return value.

@fn: ~`fn = function(a) { return a; }`;

@arg: 8px;

p {
    font-size: ~`fn("@{arg}")`;
}

1 Comment

ace! Will try that , +1 thanks - ) I've added the code from that link to your answer )
4

I think you look for this, Mixin as a function

http://lesscss.org/features/#mixins-as-functions-feature

Reading your question, I think is what you're wishing, ;D

1 Comment

Thanks @Chococroc I was reading that page before, added it to the q and having a play ..
1
// mixin
.parseInt(@string) {
    @parseInt: unit(@string, );
}

Usage:

.selector {
    .parseInt(100px);
    width: @parseInt + 10; // px will automatically be appended
}

Result:

.selector {
    width: 110px;
}

Comments

0

one of the simplest work around would be to pass the property and the value.

mixin.less

.lighter(@property, @color) {
  @{property}: multiply(white, fade(@color, 10%));
}

use.less

.my-class{
  .lighter(background-color, #FF0000);
}

Results:

.my-class{
  background-color: #fbe8eb;
}

Comments

0

This is possible from Less 3.5. You can reach into the result of a mixin call to access individual properties, meaning you can set a return value and fetch it (you can even set multiple return values if you want), and it works as expected for repeated calls.

https://lesscss.org/features/#mixins-feature-mixins-as-functions-feature

.average(@x, @y) {
   @result: ((@x + @y) / 2);
}

  
p {
  av1: .average(3, 5)[@result];
  av2: .average(3, 8)[@result];
}

Output:

p {
  av1: 4;
  av2: 5.5;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.