7

How Can I increment a variable in LESS css?

Here is the example..

@counter: 1;
.someSelector("nameOfClass", @counter);
@counter: @counter + 1;
.someSelector("nameOfClass", @counter);

The above code snippet will cause this "Syntax Error"

SyntaxError: Recursive variable definition for @counter

Is there a work around for this error? For example is there a notation like @counter++ ?

Thanks..

2
  • Isn't this is just a minified duplicate of stackoverflow.com/questions/20199298? Commented Nov 25, 2013 at 18:06
  • @seven-phases-max: probably (suspiciously similar both in question and timing). Commented Nov 25, 2013 at 18:15

1 Answer 1

9

Not Strictly Possible

See the documentation on LESS variables. Essentially, LESS variables are constants in the scope of their creation. They are lazy loaded, and cannot be "changed" in that way. The very last definition will be the one used for all in that scope. In your case an error will occur, because variables cannot reference themselves.

Consider this example:

@counter: 1;
.someSelector("nameOfClass", @counter);
@counter: 2;
.someSelector("nameOfClass1", @counter);

.someSelector(@name; @count) {
  @className: ~"@{name}";
  .@{className} {
  test: @count;
  }
}

The output will be 2 for both:

.nameOfClass {
  test: 2;
}
.nameOfClass1 {
  test: 2;
}

This is because LESS defines the @counter with the last definition of the variable in that scope. It does not pay attention to the order of the calls using @counter, but rather acts much like CSS and takes the "cascade" of the variable into consideration.

For further discussion of this in LESS, you might track discussion that occurs on this LESS feature request.

Solution is in Recursive Call Setter for the Local Variable

Seven-phases-max linked to what he believes to be a bug in LESS, but I don't think it is. Rather, it appears to me to be a creative use of recursive resetting of the counter to get the effect desired. This allows for you to achieve what you desire like so (using my example code):

// counter

.init() {
  .inc-impl(1); // set initial value
} .init();

.inc-impl(@new) {
  .redefine() {
    @counter: @new;
  }
}

.someSelector(@name) {
  .redefine(); // this sets the value of counter for this call only
  .inc-impl((@counter + 1)); // this sets the value of counter for the next call
  @className: ~"@{name}";
  .@{className} {
    test: @counter;
  }
}

.someSelector("nameOfClass");
.someSelector("nameOfClass1");

Here is the CSS output:

.nameOfClass {
  test: 1;
}
.nameOfClass1 {
  test: 2;
}

NOTE: I believe you are not strictly changing a global value here, but rather setting a new local value with each call to .someSelector. Whether this is based on buggy behavior or not is questionable, but if so, this solution may disappear in the future. For further comments of the limitations of this method, see the discussion here.

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

6 Comments

Btw. I've just remembered that there's a LESS bug/issue that can be abused to emulate such counter and variable redefinition. See this gist. But this no more than just a curious hack of course. I hope the issue will be fixed eventually.
@seven-phases-max: I disagree that it is a bug in your gist. There is a single global scoped mixin .inc() defined, which recursively sets a local variable of @counter on each call (it is not actually changing a global counter variable). So in essence it is tracking a continuous count, but serving up the variable locally, which is exactly what is needed for a solution here. I've adapted both this code and the other question to work utilizing this.
Either way, even if this considered to be an issue it's almost impossible to fix without major compiler refactoring so this behavior barely changes any time soon so I think it's pretty much safe to use. If no other less hackish solution exists of course.
Btw. this trick won't probably work in Less 1.7.0 (it turned out this is based on the #1291 issue which was fixed recently). Or maybe it will, I'm not sure needs more tests...
- update: It will work partially. Counter increases only when updated within global scope.
|

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.