Skip to content

Less language Nesting

Theo edited this page Oct 9, 2013 · 15 revisions

A ruleset can be written inside another ruleset. The compiler then removes the inner ruleset, places it right after the outer ruleset and combines their selectors. This helps to avoid repetition whenever a style sheet contains multiple rulesets with similar selectors. Common part is placed into the outer ruleset while each nested ruleset can add its own part.

Nested ruleset can use all variables and mixins defined in the outer one, but it will not contain outer selector css properties.

Simplest Case

Unless specified otherwise, inner and outer selectors are combined with the descendant combiner:

h1 {
  padding: 2 2 2 2;
  p {
    margin: 3 3 3 3;
  }
}

Output:

h1 {
  padding: 2 2 2 2;
}
h1 p {
  margin: 3 3 3 3;
}

Multiple Selectors

All nested selectors are considered to be descendants of all outer selectors:

h1, h2 {
  padding: 2 2 2 2;
  :nested, p {
    margin: 3 3 3 3;
  }
}

Output:

h1, h2 {
  padding: 2 2 2 2;
}
h1 :nested, h2 :nested, h1 p, h2 p {
  margin: 3 3 3 3;
}

Nested ruleset can use all variables and mixins defined inside the outer one:

@scope: 1;
h1, h2 {
  scope: @scope;
  :nested, p {
    scope: @scope;
  }
  @scope: 2;
}

Output:

h1, h2 {
  padding: 2;
}
h1 :nested, h2 :nested, h1 p, h2 p {
  margin: 2;
}

Joining Combiner

Prefix nested selector by and css combiner to override default "descendant" behavior:

h1, h2 {
  padding: 2 2 2 2;
  + :nested, >p {
    margin: 3 3 3 3;
  }
}

Output:

h1, h2 {
  padding: 2 2 2 2;
}
h1 + :nested, h2 + :nested, h1 > p, h2 > p {
  margin: 3 3 3 3;
}

Appender

Use appender & to override the default "outer selector comes first" behavior. Appender can be placed anywhere inside the nested selector and each nested selector can contain multiple appenders. The compilation replaces it with all outer selectors. Both combinators and whitespaces before and after the appender are respected.

Appender in the Middle

Appender is replaced by all outer selectors:

:first, :second {
  padding: 2 2 2 2;
  h1&:hover, h2 & :visit {
    margin: 3 3 3 3;
  }
}

Output:

:first,
:second {
  padding: 2 2 2 2;
}
h1:first:hover,
h1:second:hover,
h2 :first :visit,
h2 :second :visit {
  margin: 3 3 3 3;
}

Multiple Appenders

Multiple appenders generate all combinations of outer selectors:

:first, :second {
  padding: 2 2 2 2;
  h1&:hover& {
    margin: 3 3 3 3;
  }
}

Output:

:first,
:second {
  padding: 2 2 2 2;
}
h1:first:hover:first,
h1:first:hover:second,
h1:second:hover:first,
h1:second:hover:second {
  margin: 3 3 3 3;
}

Deep Nesting

Nested rules can go arbitrarily deep:

h1 {
  padding: 2 2 2 2;
  p {
    margin: 3 3 3 3;
    &:hover {
      width: 2;
    }
  }
}

Output:

h1 {
  padding: 2 2 2 2;
}
h1 p {
  margin: 3 3 3 3;
}
h1 p:hover {
  width: 2;
}

Combinators and Whitespaces

Both combinators and whitespaces before and after the appender are respected:

h1, h2 {
  padding: 2 2 2 2;
  &:direct, & + :child, & :descendant {
    margin: 3 3 3 3;
  }
}
:first, :second {
  padding: 2 2 2 2;
  descendant &, child + &, direct& {
    margin: 3 3 3 3;
  }
}

Output:

h1, h2 {
  padding: 2 2 2 2;
}
h1:direct, h2:direct,
h1 + :child, h2 + :child,
h1 :descendant, h2 :descendant {
  margin: 3 3 3 3;
}
:first, :second {
  padding: 2 2 2 2;
}
descendant :first, descendant :second,
child + :first, child + :second,
direct:first, direct:second {
  margin: 3 3 3 3;
}

Combinator Conflict

In case of conflict, the inner selector combinator wins:

> h1 {
  name + & {
    declaration: 1 2;
  }
}

Output:

name + h1 {
  declaration: 1 2;
}
Clone this wiki locally