Less Immediate Parent Selector

Less Immediate Parent Selector

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.

LESS parent selector for first parent

You have put the & (parent selector) at the wrong place. It shouldn't be put after the selector, instead it should be before the .. Setting the & after the selector means the whole parent selector (from the topmost selector) will be appended at the end of the current selector instead of getting inserted before (which is what you need for .header .menu.no-borderradius or ul li.active.

.header {
.menu {
border-radius: 5px;
&.no-borderradius { /* here & is equal to .header .menu */
background-image: url('images/button-background.png');
}
}
}

ul {
li {
&.active, /* here & is equal to ul li */
&:hover {
color: red;
}
}
}

Regarding the update to the question - it is currently not possible to achieve ul li.active a using the below structure as parent selector means the entire chain of selectors till the current level and not just the immediate parent. There is no way to just pick the immediate parent.

ul {
li {
a {
.active &,
&:hover {
color: red;
}
}
}
}

The only option currently possible is to write it like below:

ul {
li {
&.active a,
a:hover {
color: red;
}
}
}

There is an open feature request for parent selectors to have targets but there is no decision on by when this would be done.

LESS CSS How to capture parent selector in variable

You can possible solve your issue by using the parent reference & to (change selector order)[http://lesscss.org/features/#parent-selectors-feature-changing-selector-order]

.media {
&__body{
color: green;
}
&.-reverse & {
&__body {
color: red;
}
}
}

compiles into CSS code as follows:

.media__body {
color: green;
}
.media.-reverse .media__body {
color: red;
}

LESS - styling classes differently dependent on the parent element

Well, you could always do

.zero {
span & { color: #fff; }
div & { color: #389c40; }
}

Apply a tag selector to the immediate parent of a rule within a deeply-nested structure

Looks like you're getting tangled up in wanting über-optimized LESS. If I understand correctly, either way your compiled CSS will be

article .foo {
general `article .foo` styles
}
article a.foo {
additional styles specific to `article a.foo`
}

In LESS you could write that as is, or you could do

article {
.foo {
general `article .foo` styles
}
a.foo {
additional styles specific to `article a.foo`
}
}

or depending on your styles you might be able to do

article .foo {
general `article .foo` styles
}
a.foo {
additional styles specific to `a.foo`
}

Specify an attribute value using the parent selector in LESS?

The parent selector (&) only holds a reference to an entire complex selector, with the option to extend the selector provided that you use the entire thing as a base:

.one > .two {
&::after, &::before {
// Compiles to .one > .two::after, .one > .two::before
}
& + .three {
// Compiles to .one > .two + .three

&-suffix {
// Compiles to .one > .two + .three-suffix
}
}
}

It cannot be used to reference a part of a compound or simple selector, in particular it cannot be used to reference just the attribute name in an attribute selector. You'll have to stick with vanilla CSS.

The reason that abomination doesn't work is because both preprocessors expect all selectors in style rules to be valid; [some-attribute is not a valid selector. You could write a mixin and/or use selector interpolation, but it still has to result in a valid selector when used with a style rule, since the compiler can't assume that you won't be using the selector in its own set of style declarations (though of course, whether a preprocessor should be controlling the author in this way is up for debate...).



Related Topics



Leave a reply



Submit