16

Is it possible to get a parent's parent?

I tried & & { } but that didn't work.

I'm trying to style a child element based on it's grandparent.

chovy
  • 59,357
  • 43
  • 187
  • 234

4 Answers4

20

Depends on Code Structure, and may Require Some Repetition of Code

You cannot do it directly in most cases (see second example for exception).

If Grandparent is an element

This requires some repetition, but does allow for the grandparent to not be the outermost wrapper (so there could be a great grandparent).

LESS

grandparent {  
  /* grandparent styles */
  parent {
    /* parent styles */
    child {
      /* child styles */
    }
  }
  &.specialGrandpa {
    child {
      /* child styles with special Grandpa */
    }
  }
  &.specialGrandma {
    child {
      /* child styles with special Grandma*/
    }
  }
}

CSS Output

grandparent {
  /* grandparent styles */    
}
grandparent parent {
  /* parent styles */    
}
grandparent parent child {
  /* child styles */    
}
grandparent.specialGrandpa child {
  /* child styles with special Grandpa */    
}
grandparent.specialGrandma child {
  /* child styles with special Grandma*/    
}

If Grandparent is a class, ID, etc., and is the outermost wrapper

No repetition involved here, but you cannot have a great grandparent in the mix. Also this is only for LESS 1.3.1+ version (earlier version incorrectly add a space):

LESS

.grandparent {  
  /* grandparent styles */
  .parent {
    /* parent styles */
    .child {
      /* child styles */
      .specialGrandparent& {
          /* child styles with special grandparent*/
      }
    }
  }
}

CSS Output

.grandparent {
  /* grandparent styles */    
}
.grandparent .parent {
  /* parent styles */   
}
.grandparent .parent .child {
  /* child styles */    
}
.specialGrandparent.grandparent .parent .child {
  /* child styles with special grandparent*/   
}

This code works by appending to the "front" of the grandparent selector, so that is why the grandparent must be a class, ID, or other selector itself.

Addendum

Based on comment about desire to have a red background when the span is empty. This does not put the background on the parent, but "fakes" it using the child.

span:empty:after {
    content: '';
    position: absolute;
    top: -1px;
    right: -10px;
    left: -1px;
    bottom: -10px;
    display: block;
    background-color: red;
    z-index: -1;
}
ScottS
  • 68,932
  • 12
  • 117
  • 139
  • Trying to do what you're suggesting...but it doesn't work: http://fiddlesalad.com/less/not-empty-parent-selector/ -- note the last less rule. I'm trying to style the parent div with background of red when its child span is not empty. – chovy Jun 25 '13 at 22:44
  • Your problem is that you are trying to do something CSS cannot do, and a preprocessor like LESS will not help (since all it does is produce valid CSS). LESS, being a preprocessor, has no idea whether the `span` is empty or not (the processing is done _before_ it is served to the browser; it has no knowledge of the state of the html), and [CSS cannot affect a parent element based off the state of a child element](http://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector). You need to use javascript to do what you want. – ScottS Jun 25 '13 at 22:54
  • @chovy: However, a work around is to use an `span:empty:after` styled to apply the background. Code given as addendum to my answer. – ScottS Jun 25 '13 at 23:06
  • Not sure what span:empty:after gets me vs. what I had. But I see I cannot write a rule based on an ancestor...so I'll have to use JS at runtime. – chovy Jun 26 '13 at 20:02
  • @chovy: I have not used "fiddlesalad.com" before, and could not figure out how to get it to save. But if you plug the `span:empty:after` code into the place of your non-working code, you will see what it gets you (a red background to the `div` when the `span` is empty). – ScottS Jun 26 '13 at 22:16
7

You cannot traverse arbitrarily up the DOM with less selectors. Use javascript instead.

The & in less stands for declared selector one level up. A shortcut for already defined rule. As opposed to what you allegedly seek.

Andrevinsky
  • 536
  • 3
  • 12
5

According to LESS's parent selectors feature, it's possible to change selector order by putting the & after the items in your nest, thereby accessing the item's parent's parent.

LESS code:

span {
  color:red;
  h6 & {
    color:white;
    div & {
      color:blue;
    }
  }
}

CSS result:

span {
  color: red;
}
h6 span {
  color: white;
}
div h6 span {
  color: blue;
}
itsmikem
  • 1,813
  • 2
  • 20
  • 26
2

You can use a mixin, then you can pass variables to it based on grandparent selector specifics.

Example:

ul {
    .color-links(@color) {
        li a { // any link inside a child li
            color: @color;
        }
    }
    &.red {
        .color-links(#ff0000);
    }
    &.green {
        .color-links(#00ff00);
    }
}
Meligy
  • 32,897
  • 11
  • 79
  • 103