Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a way for top level css rulesets to be created using local var scope #893

Closed
bthule opened this issue Aug 11, 2012 · 7 comments
Closed

Comments

@bthule
Copy link

bthule commented Aug 11, 2012

I would like to use less to aggregate all my less files, css files, bootstrap less files, and so on. To do this effectively, there needs to be a way for multiple imports to contribute to the top level css rulesets but have their own local var scopes.

The problem is that all selectors being generated in the top level share the same global var scope. Currently, if a mixin is used to generate css rulesets at the top level, and if that mixin sets a var, then it will change that var for everything else using it at the top level. This makes sense, after all, it is named a "mixin". But there is no "function" analogy in less. A "function" would use it's own local scope for satisfying variables and mixins, and would contribute css rulesets without affecting the containing scopes vars or mixins.

An example, using @function as the keyword:

// example 1
@test: #000;
@function .myFunction { 
   @test: #fff;  
    .baz: { color: @test;}
}
.myFunction()
.bar: { color: @test;}

outputs:

.baz { color: #ffffff; }
.bar { color: #000000; }

This naming seems backwards compatible since using @ at the beginning of a selector name is currently not allowed.

Another, possibly simpler solution, but not as powerful would be to have keyword that unwraps a level of nesting using the local scope of the nested level to generate the rulesets, and then use the rulesets at the parent level. An example might be clearer:

Using the name @localize for the keyword, it could alternatively be named @unwrap, @scoped, @unit, or something else

// example 2
@test: #000;
@localize { 
   @test: #fff;  
    .baz: { color: @test;}
}
.bar: { color: @test;}

outputs:

.baz { color: #ffffff; }
.bar { color: #000000; }

In both these examples, the parent's scope would contribute it's mixins and vars to the nested scope. These are "copied" to the local scope, and any changes to those mixins or vars in the local scope do not affect the parents scope.

@bthule
Copy link
Author

bthule commented Aug 11, 2012

Wow, so it just came to me that maybe this whole idea is just a big workaround for what seems to be a bug in less.js (See issue #297).

@agatronic or other, please close this issue if less.js will be changed to make variables work like it does in dotless and lessphp.

@lukeapage
Copy link
Member

You can use #id to namespace ..

e.g.

#namespace {
    .mixin() {
        color: #fff;
    }
}
#namespace > .mixin();

plus there is a request for allowing imports inside mixins.. which would do what you are asking, so I don't think we need any extra syntax for this.

@bthule
Copy link
Author

bthule commented Aug 12, 2012

I think I found a bug.

The ordering of a var declaration and a mixin call will change the css output.

Here is an example:



#namespace {
    .mixin() {
        @test: #FFF;
        .shouldHaveFs {
           color: @test;
        }    
    }
}

.shouldHaveZeros {
    color: @test;
}

// the ordering of these next two lines changes the output!
@test: #000;
#namespace > .mixin();

This outputs a desirable result:

.shouldHaveZeros{color:#000000;}
.shouldHaveFs{color:#ffffff;}

But if you change the order of the last two lines, then it changes the output to:

.shouldHaveFs{color:#ffffff;}
.shouldHaveZeros{color:#ffffff;}

I just figured this nuance out, and as long as I am careful never to define a global var before I call a mixin that changes it, then I shouldn't have a problem. However, this nuance seems like a bug. And if not, then it is at least confusing (but may be less so if documented)

Anyway, based on this nuance, this is how less currently works:

  1. declaring a var and then subsequently using a mixin that changes it will allow the mixin to change the var in the caller's scope.
  2. calling a mixin, then declaring a var will makes the mixin use a local var, and will not affect the var in the caller's scope

I think less would be much more understandable if this is how it worked instead:

  1. a mixin can always change the vars in the caller's scope
  2. a function can never change the vars in the caller's scope

If less was changed to work like this, then it would get rid of the confusing mixin call/var declaration ordering dilemma. The big question is how to declare something as a function vs a mixin. Adding a @function selector seems like a good way to help accomplish that. I would recommend also allow adding a @mixin selector so that the less language is consistent. If neither @mixin nor @function is used on a mixin definition, then a default would be used. I lean towards @function being the default because it does less work (a @mixin is a fancy @function that allows it to change vars on the caller's scope). It would be ideal if the default decision could be made knowing which one would break fewer existing code, but it is difficult to know what order the existing code would call mixins and declare vars.

@bthule
Copy link
Author

bthule commented Aug 12, 2012

plus there is a request for allowing imports inside mixins.. which would do what you are asking, so I don't think we need >any extra syntax for this.

In Less 1.3.0, it seems you can already use imports inside mixins. It seems to work fine for me, is there known issues?

@bthule
Copy link
Author

bthule commented Aug 12, 2012

Of course, all of this would be a moot if less.js was changed to be like dotless so that it "does not leak variables from a called mixin into the scope it is called from"
+1 vote for that

@nathanielks
Copy link

similar issue: #905

@lukeapage
Copy link
Member

think discussion can be moved to #297

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants