-
Notifications
You must be signed in to change notification settings - Fork 45
Less Language Namespaces
Rulesets with simple names acts also as namespaces. Namespace encapsulates a group of mixins under common name. They are used to avoid naming conflicts in bigger projects and to encapsulate/isolate a group of mixins from outside world.
Only class and id rulesets can be used as a namespace e.g., the selector must have form #name
or .name
.
Any mixin nested inside a namespace ruleset belongs to that namespace and can be called using namespace > mixin(param1, ..., paramn)
syntax. The symbol greater >
is optional, slightly shorter namespace mixin(param1, ..., paramn)
syntax is valid too.
Declare namespace and use its mixins:
//declare namespace with two mixins
#ns {
.square(@param) {
width: @param;
height: @param;
}
.color(@color) {
color: @color;
}
}
.box {
//use the namespace
#ns > .square(10px);
#ns .color(#ff00ff);
}
Compiles to:
.box {
width: 10px;
height: 10px;
color: #ff00ff;
}
It is legal to nest a namespace inside another one. In addition, mixins inside the namespace are matched as usually, e.g. all matching mixins are going to be used. Following less is equivalent to the previous one:
//declare namespace with one mixin
#outer {
#ns {
.square(@param) {
width: @param;
}
.square(@param) {
height: @param;
}
}
}
.box {
//use the namespace
#outer > #ns > .square(10px);
}
Compiles to:
.box {
width: 10px;
height: 10px;
}
Top level namespace references are legal as long as the referenced mixin contains only nested rulesets and no declarations:
#namespace {
//mixin without declarations
.mixin() {
nested {
color: blue;
}
}
}
//top level namespace reference
#namespace .mixin();
compiles into:
nested {
color: blue;
}
As usually, a namespace is valid withing the whole scope where it has been defined and can be used before it has been defined. If multiple namespaces match the reference, all of them are going to be used.
Next less snipped it compiled into the same result as all previous:
.box {
//use the namespace
#ns > .square(10px);
}
// namespace is split into two parts - part 1
#ns {
.square(@param) {
width: @param;
}
}
// namespace is split into two parts - part 2
#ns {
.square(@param) {
height: @param;
}
}
Namespace scoping chapter address two different issues:
- Which variables and mixins are available inside the namespace.
- If multiple scopes contains namespaces with conflicting names, which one is going to be used.
Each issue is addressed in separate section.
Any mixin declared inside the namespace can use mixins and variables declared in both its declaration and caller scope. The declaration scope takes precedence over the caller scope.
Create a bunch of overriding variables within each scope and see which one wins:
#outer {
#ns {
.square(@priority1, @priority2) {
priority1: @priority1;
priority2: @priority2;
priority3: @priority3;
priority4: @priority4;
priority5: @priority5;
priority6: @priority6;
@priority1: "inside mixin";
}
}
@priority1: "declaration scope";
@priority2: "declaration scope";
@priority3: "declaration scope";
}
.box {
.box {
//call the mixin
#outer > #ns > .square("argument", "argument");
@priority1: "caller scope";
@priority2: "caller scope";
@priority3: "caller scope";
@priority4: "caller scope";
@priority5: "caller scope";
}
@priority1: "caller scope - deeper";
@priority2: "caller scope - deeper";
@priority3: "caller scope - deeper";
@priority4: "caller scope - deeper";
@priority6: "caller scope - deeper";
}
@priority1: "declaration scope - deeper";
@priority2: "declaration scope - deeper";
@priority3: "declaration scope - deeper";
@priority4: "declaration scope - deeper";
Compiles into:
.box {
priority1: "inside mixin";
priority2: "argument";
priority3: "declaration scope";
priority4: "declaration scope - deeper";
priority5: "caller scope";
priority6: "caller scope - deeper";
}
Note: Less.js has one known bug in handling of lazy-loaded namespaces https://github.com/cloudhead/less.js/issues/996 .
Namespaces references are relative to current scope. Less looks for matching namespace within current scope first. If a mixin is found, the search is stopped. The search continues into parent scope only if the last searched scope contains no matching element.
Example:
#ns {
.mixin() {
declaration: "global namespace";
}
}
.box {
#ns {
.mixin() {
declaration: "local namespace";
}
}
//use the namespace
#ns > .mixin();
}
Result:
.box {
declaration: "local namespace";
}