37

Less allows one to select the parent selector (http://lesscss.org/features/#parent-selectors-feature)

How does one get the immediate parent selector, not the root parent selector?

CMCDragonkai
  • 6,222
  • 12
  • 56
  • 98
  • I'm really wondering what the use case for this situation is. Getting the immediate parent only serves to make your styling rule less specific. If you REALLY want to do that (which is rarely, if at all useful) you should use the parent selector in a specific section of less where it's only nested in the immediate parent. – Hans Roerdinkholder Feb 24 '14 at 10:49
  • 1
    Well alot of people are asking for this on this SASS article (see comments) http://thesassway.com/intermediate/referencing-parent-selectors-using-ampersand – CMCDragonkai Feb 24 '14 at 11:13
  • And the solution is stated in the reply made to the first person asking it. I see a few people commenting that they want the immediate parent, but again no one is giving a clear use case for it. – Hans Roerdinkholder Feb 24 '14 at 11:15
  • See also [#1075](https://github.com/less/less.js/issues/1075). – seven-phases-max Feb 24 '14 at 12:06
  • 1
    @HansRoerdinkholder my use case is that I want to override a color based on a class which is defined on the parent but not on the root. i.e. `^ .dark-theme & { color: black; }` where ^ is my pseudocode for going up one level and not all the way to the root. I want to define this override in my less file in the same location as the original color to make it easier in the future to find – Simon_Weaver Sep 27 '14 at 22:09

1 Answers1

41

A Base Example

It partly depends upon how you structure your LESS code. There is currently no way to do this with a normal nested structure. However, take the following example, where the .grandchild is our final target in all cases (it must be the outermost level--I called this "end target grouping" in a previous answer before LESS added documentation about using & as a parent selector):

LESS

.grandchild {
  grandchild: 1;
  .child & {
    child: 1;
    .parent & {
      parent: 1;
      .grandparent & {
        grandparent: 1;

      }
    }
  }
}

CSS Output

.grandchild  {
  grandchild: 1;
}
.child .grandchild  {
  child: 1;
}
.parent .child .grandchild  {
  parent: 1;
}
.grandparent .parent .child .grandchild  {
  grandparent: 1;
}

As you can see, any code nested in the first level only has the end target of .grandchild in its selector string. Each level one goes "down" in the nest, one is actually going "up" in selector specificity. So to target just the "immediate parent" for the selector string, place it in the .child of this example.

Hovers Still Work

LESS

.grandchild {
  grandchild: 1;
  &:hover {
    grandchildhover: 1;
  }
  .child & {
    child: 1;
    .parent & {
      parent: 1;
      .grandparent & {
        grandparent: 1;
        &:hover {
          grandchildhover: 1;
        }
      }
    }
  }
}

This will add to the above css these two outputs:

.grandchild:hover {
  grandchildhover: 1;
}

.grandparent .parent .child .grandchild:hover {
  grandchildhover: 1;
}

Skip Generations

You can code it to skip some generations, like so:

LESS

.grandchild {
  grandchildonly: 1;
  .child & {
    withchild: 1;
    .parent & {
      withparentchild: 1;
    }
  }
  .parent & {
    skipgenchild: 1;
  }
}

CSS Output

.grandchild {
  grandchildonly: 1;
}
.child .grandchild {
  withchild: 1;
}
.parent .child .grandchild {
  withparentchild: 1;
}
.parent .grandchild {
  skipgenchild: 1;
}

Abstracted

There are various ways this could be abstracted out, such that the code does not give the appearance of a nested look (which could confuse a user). Something like this is one way (output similar to that given in first and second examples above):

.addParent(@parent) { 
  @parentescaped: e(@parent); 
  @{parentescaped} & {.setWithParentProps(@parent);}
}

.grandchild {
  grandchild: 1;
  &:hover {
    grandchildhover: 1;
  }
  .addParent('.child');
  .setWithParentProps('.child'){
    child: 1;
    .addParent('.parent');
  }
  .setWithParentProps('.parent'){
    parent: 1;
    .addParent('.grandparent');
  }
  .setWithParentProps('.grandparent'){
    grandparent: 1;
    &:hover {
      morespecifichover: 1;
    }
  }
}

Final Comments

As seven-phases-max linked to in his comment, there is talk of adding generational precision within a normal nested context. The solution given here requires one to think "opposite" of nesting, but rather think only about the element being targeted. So the way to add a .grandchild into another selector would not be this mixin:

LESS (expecting to add a parent by normal nesting)

.another-generational-parent {
  .grandchild;
}

CSS Output

.another-generational-parent {
  grandchildonly: 1;
}
.child .another-generational-parent {
  withchild: 1;
}
.parent .child .another-generational-parent {
  withparentchild: 1;
}

It would be best to add it into the original code according to the proper place, but if that is not possible, then some repetition is needed (unless you set up some way in the original code to "insert" parents through creative mixin calling--I have no time to devout to that here).

.parent .child .grandchild {
  .another-generational-parent & {
     another-generational-parent: 1;
  }
}

Whether such opposite coding can be useful or not all depends upon one's goals and desires in organizing the LESS code.

Community
  • 1
  • 1
ScottS
  • 71,703
  • 13
  • 126
  • 146