LaVOZs

The World’s Largest Online Community for Developers

'; Is there a CSS parent selector? - LavOzs.Com

How do I select the <li> element that is a direct parent of the anchor element?

As an example, my CSS would be something like this:

li < a.active {
    property: value;
}

Obviously there are ways of doing this with JavaScript, but I'm hoping that there is some sort of workaround that exists native to CSS Level 2.

The menu that I am trying to style is being spewed out by a CMS, so I can't move the active element to the <li> element... (unless I theme the menu creation module which I'd rather not do).

Any ideas?

There is currently no way to select the parent of an element in CSS.

If there was a way to do it, it would be in either of the current CSS selectors specs:

In the meantime, you'll have to resort to JavaScript if you need to select a parent element.


The Selectors Level 4 Working Draft includes a :has() pseudo-class that works the same as the jQuery implementation. As of 2019, this is still not supported by any browser.

Using :has() the original question could be solved with this:

li:has(> a.active) { /* styles to apply to the li tag */ }

I don’t think you can select the parent in CSS only.

But as you already seem to have an .active class, it would be easier to move that class to the li (instead of the a). That way you can access both the li and the a via CSS only.

You can use this script:

*! > input[type=text] { background: #000; }

This will select any parent of a text input. But wait, there's still much more. If you want, you can select a specified parent:

.input-wrap! > input[type=text] { background: #000; }

Or select it when it's active:

.input-wrap! > input[type=text]:focus { background: #000; }

Check out this HTML:

<div class="input-wrap">
    <input type="text" class="Name"/>
    <span class="help hide">Your name sir</span>
</div>

You can select that span.help when the input is active and show it:

.input-wrap! .help > input[type=text]:focus { display: block; }

There are many more capabilities; just check out the documentation of the plugin.

BTW, it works in Internet Explorer.

As mentioned by a couple of others, there isn't a way to style an element's parent/s using just CSS but the following works with jQuery:

$("a.active").parents('li').css("property", "value");

Yes: :has()

Browser support: none

There is no parent selector; just the way there is no previous sibling selector. One good reason for not having these selectors is because the browser has to traverse through all children of an element to determine whether or not a class should be applied. For example, if you wrote:

body:contains-selector(a.active) { background: red; }

Then the browser will have to wait until it has loaded and parsed everything until the </body> to determine if the page should be red or not.

The article Why we don't have a parent selector explains it in detail.

There isn't a way to do this in CSS 2. You could add the class to the li and reference the a:

li.active > a {
    property: value;
}

Try to switch a to block display, and then use any style you want. The a element will fill the li element, and you will be able to modify its look as you want. Don't forget to set li padding to 0.

li {
  padding: 0;
  overflow: hidden;
}
a {
  display: block;
  width: 100%;
  color: ..., background: ..., border-radius: ..., etc...
}
a.active {
  color: ..., background: ...
}

The CSS selector “General Sibling Combinator” could maybe used for what you want:

E ~ F {
    property: value;
}

This matches any F element that is preceded by an E element.

Not in CSS 2 as far as I'm aware. CSS 3 has more robust selectors but is not consistently implemented across all browsers. Even with the improved selectors, I don't believe it will accomplish exactly what you've specified in your example.

I know the OP was looking for a CSS solution but it is simple to achieve using jQuery. In my case I needed to find the <ul> parent tag for a <span> tag contained in the child <li>. jQuery has the :has selector so it's possible to identify a parent by the children it contains:

$("ul:has(#someId)")

will select the ul element that has a child element with id someId. Or to answer the original question, something like the following should do the trick (untested):

$("li:has(.active)")

This is the most discussed aspect of the Selectors Level 4 specification. With this, a selector will be able to style an element according to its child by using an exclamation mark after the given selector (!).

For example:

body! a:hover{
   background: red;
}

will set a red background-color if the user hovers over any anchor.

But we have to wait for browsers' implementation :(

The pseudo element :focus-within allows a parent to be selected if a descendent has focus.

An element can be focused if it has a tabindex attribute.

Browser support for focus-within

Tabindex

Example

.click {
  cursor: pointer;
}

.color:focus-within .change {
  color: red;
}

.color:focus-within p {
  outline: 0;
}
<div class="color">
  <p class="change" tabindex="0">
    I will change color
  </p>
  <p class="click" tabindex="1">
    Click me
  </p>
</div>

You might try to use hyperlink as the parent, and then change the inner elements on hover. Like this:

a.active h1 {color:red;}

a.active:hover h1 {color:green;}

a.active h2 {color:blue;}

a.active:hover h1 {color:yellow;}

This way you can change the style in multiple inner tags, based on the rollover of the parent element.

Currently there is no parent selector & it is not even being discussed in any of the talks of W3C. You need to understand how CSS is evaluated by the browser to actually understand if we need it or not.

There is a lot of technical explanation here.

Jonathan Snook explains how CSS is evaluated.

Chris Coyier on the talks of Parent selector.

Harry Roberts again on writing efficient CSS selectors.

But Nicole Sullivan has some interesting facts on positive trends.

These people are all top class in the field of front end development.

Just an idea for horizontal menu...

Part of HTML

<div class='list'>
  <div class='item'>
    <a>Link</a>
  </div>
  <div class='parent-background'></div>
  <!-- submenu takes this place -->
</div>

Part of CSS

/* Hide parent backgrounds... */
.parent-background {
  display: none; }

/* ... and show it when hover on children */
.item:hover + .parent-background {
  display: block;
  position: absolute;
  z-index: 10;
  top: 0;
  width: 100%; }

Updated demo and the rest of code

Another example how to use it with text-inputs - select parent fieldset

There's a plugin that extends CSS to include some non-standard features that can really help when designing websites. It's called EQCSS.

One of the things EQCSS adds is a parent selector. It works in all browsers, Internet Explorer 8 and up. Here's the format:

@element 'a.active' {
  $parent {
    background: red;
  }
}

So here we've opened an element query on every element a.active, and for the styles inside that query, things like $parent make sense, because there's a reference point. The browser can find the parent, because it's very similar to parentNode in JavaScript.

Here's a demo of $parent and another $parent demo that works in Internet Explorer 8, as well as a screenshot in case you don't have Internet Explorer 8 around to test with.

EQCSS also includes meta-selectors: $prev for the element before a selected element and $this for only those elements that match an element query, and more.

Here's a hack using pointer-events with hover:

<!doctype html>
<html>
	<head>
		<title></title>
		<style>
/* accessory */
.parent {
	width: 200px;
	height: 200px;
	background: gray;
}
.parent, 
.selector {
	display: flex;
	justify-content: center;
	align-items: center;
}
.selector {
	cursor: pointer;
	background: silver;
	width: 50%;
	height: 50%;
}
		</style>
		<style>
/* pertinent */
.parent {
	background: gray;
	pointer-events: none;
}
.parent:hover {
	background: fuchsia;
}
.parent 
.selector {
	pointer-events: auto;
}
		</style>
	</head>
	<body>
		<div class="parent">
			<div class="selector"></div>
		</div>
	</body>
</html>

Technically there is no direct way to do this. However, you can sort that out with either jQuery or JavaScript.

However, you can do something like this as well.

a.active h1 {color: blue;}
a.active p {color: green;}

jQuery

$("a.active").parents('li').css("property", "value");

If you want to achieve this using jQuery here is the reference for the jQuery parent selector.

It's now 2019, and the latest draft of the CSS Nesting Module actually has something like this. Introducing @nest at-rules.

3.2. The Nesting At-Rule: @nest

While direct nesting looks nice, it is somewhat fragile. Some valid nesting selectors, like .foo &, are disallowed, and editing the selector in certain ways can make the rule invalid unexpectedly. As well, some people find the nesting challenging to distinguish visually from the surrounding declarations.

To aid in all these issues, this specification defines the @nest rule, which imposes fewer restrictions on how to validly nest style rules. Its syntax is:

@nest = @nest <selector> { <declaration-list> }

The @nest rule functions identically to a style rule: it starts with a selector, and contains declarations that apply to the elements the selector matches. The only difference is that the selector used in a @nest rule must be nest-containing, which means it contains a nesting selector in it somewhere. A list of selectors is nest-containing if all of its individual complex selectors are nest-containing.

(Copy and pasted from the URL above).

Example of valid selectors under this specification:

.foo {
  color: red;
  @nest & > .bar {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   .foo > .bar { color: blue; }
 */

.foo {
  color: red;
  @nest .parent & {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   .parent .foo { color: blue; }
 */

.foo {
  color: red;
  @nest :not(&) {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   :not(.foo) { color: blue; }
 */

The W3C excluded such a selector because of the huge performance impact it would have on a browser.

The short answer is NO; we don't have a parent selector at this stage in CSS, but if you don't have to swap the elements or classes anyway, the second option is using JavaScript. Something like this:

var activeATag = Array.prototype.slice.call(document.querySelectorAll('a.active'));

activeATag.map(function(x) {
  if(x.parentNode.tagName === 'LI') {
    x.parentNode.style.color = 'red'; // Your property: value;
  }
});

Or a shorter way if you use jQuery in your application:

$('a.active').parents('li').css('color', 'red'); // Your property: value;

Although there is no parent selector in standard CSS at present, I am working on a (personal) project called axe (ie. Augmented CSS Selector Syntax / ACSSSS) which, among its 7 new selectors, includes both:

  1. an immediate parent selector < (which enables the opposite selection to >)
  2. an any ancestor selector ^ (which enables the opposite selection to [SPACE])

axe is presently in a relatively early BETA stage of development.

See a demo here:

http://rounin.co.uk/projects/axe/axe2.html

(compare the two lists on the left styled with standard selectors and the two lists on the right styled with axe selectors)

At least up to and including CSS 3 you cannot select like that. But it can be done pretty easily nowadays in JavaScript, you just need to add a bit of vanilla JavaScript, notice that the code is pretty short.

cells = document.querySelectorAll('div');
[].forEach.call(cells, function (el) {
    //console.log(el.nodeName)
    if (el.hasChildNodes() && el.firstChild.nodeName=="A") {
        console.log(el)
    };
});
<div>Peter</div>
<div><a href="#">Jackson link</a></div>
<div>Philip</div>
<div><a href="#">Pullman link</a></div>

Any ideas?

CSS 4 will be fancy if it adds some hooks into walking backwards. Till then it is possible (though not advisable) to use checkbox and/or radio inputs to break the usual way that things are connected, and through that also allow CSS to operate outside of its normal scope...

/* Hide things that may be latter shown */
.menu__checkbox__selection,
.menu__checkbox__style,
.menu__hidden {
  display: none;
  visibility: hidden;
  opacity: 0;
  filter: alpha(opacity=0); /* Old Microsoft opacity */
}


/* Base style for content and style menu */
.main__content {
  background-color: lightgray;
  color: black;
}

.menu__hidden {
  background-color: black;
  color: lightgray;
  /* Make list look not so _listy_ */
  list-style: none;
  padding-left: 5px;
}

.menu__option {
  box-sizing: content-box;
  display: block;
  position: static;
  z-index: auto;
}

/* &#9660; - \u2630 - Three Bars */
/*
.menu__trigger__selection::before {
  content: '\2630';
  display: inline-block;
}
*/

/* &#9660; - Down Arrow */
.menu__trigger__selection::after {
  content: "\25BC";
  display: inline-block;
  transform: rotate(90deg);
}


/* Customize to look more `select` like if you like */
.menu__trigger__style:hover,
.menu__trigger__style:active {
  cursor: pointer;
  background-color: darkgray;
  color: white;
}


/**
 * Things to do when checkboxes/radios are checked
 */

.menu__checkbox__selection:checked + .menu__trigger__selection::after,
.menu__checkbox__selection[checked] + .menu__trigger__selection::after {
  transform: rotate(0deg);
}

/* This bit is something that you may see elsewhere */
.menu__checkbox__selection:checked ~ .menu__hidden,
.menu__checkbox__selection[checked] ~ .menu__hidden {
  display: block;
  visibility: visible;
  opacity: 1;
  filter: alpha(opacity=100); /* Microsoft!? */
}


/**
 * Hacky CSS only changes based off non-inline checkboxes
 * ... AKA the stuff you cannot unsee after this...
 */
.menu__checkbox__style[id="style-default"]:checked ~ .main__content {
  background-color: lightgray;
  color: black;
}

.menu__checkbox__style[id="style-default"]:checked ~ .main__content .menu__trigger__style[for="style-default"] {
  color: darkorange;
}

.menu__checkbox__style[id="style-one"]:checked ~ .main__content {
  background-color: black;
  color: lightgray;
}

.menu__checkbox__style[id="style-one"]:checked ~ .main__content .menu__trigger__style[for="style-one"] {
  color: darkorange;
}

.menu__checkbox__style[id="style-two"]:checked ~ .main__content {
  background-color: darkgreen;
  color: red;
}

.menu__checkbox__style[id="style-two"]:checked ~ .main__content .menu__trigger__style[for="style-two"] {
  color: darkorange;
}
<!--
  This bit works, but will one day cause troubles,
  but truth is you can stick checkbox/radio inputs
  just about anywhere and then call them by id with
  a `for` label. Keep scrolling to see what I mean
-->
<input type="radio"
       name="colorize"
       class="menu__checkbox__style"
       id="style-default">
<input type="radio"
       name="colorize"
       class="menu__checkbox__style"
       id="style-one">
<input type="radio"
       name="colorize"
       class="menu__checkbox__style"
       id="style-two">


<div class="main__content">

  <p class="paragraph__split">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  </p>

  <input type="checkbox"
         class="menu__checkbox__selection"
         id="trigger-style-menu">
  <label for="trigger-style-menu"
         class="menu__trigger__selection"> Theme</label>

  <ul class="menu__hidden">
    <li class="menu__option">
      <label for="style-default"
             class="menu__trigger__style">Default Style</label>
    </li>

    <li class="menu__option">
      <label for="style-one"
             class="menu__trigger__style">First Alternative Style</label>
    </li>

    <li class="menu__option">
      <label for="style-two"
             class="menu__trigger__style">Second Alternative Style</label>
    </li>
  </ul>

  <p class="paragraph__split">
    consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
    cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
    proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>

</div>

No, you cannot select the parent in CSS only.

But as you already seem to have an .active class, it would be easier to move that class to the li (instead of the a). That way you can access both the li and the a via CSS only.

It's possible with ampersand in Sass:

h3
  font-size: 20px
  margin-bottom: 10px
  .some-parent-selector &
    font-size: 24px
    margin-bottom: 20px

CSS output:

h3 {
  font-size: 20px;
  margin-bottom: 10px;
}
.some-parent-selector h3 {
  font-size: 24px;
  margin-bottom: 20px;
}

Changing parent element based on child element can currently only happen when we have an <input> element inside the parent element. When an input gets focus, its corresponding parent element can get affected using CSS.

Following example will help you understand using :focus-within in CSS.

.outer-div {
  width: 400px;
  height: 400px;
  padding: 50px;
  float: left
}

.outer-div:focus-within {
  background: red;
}

.inner-div {
  width: 200px;
  height: 200px;
  float: left;
  background: yellow;
  padding: 50px;
}
<div class="outer-div">
  <div class="inner-div">
    I want to change outer-div(Background color) class based on inner-div. Is it possible?
    <input type="text" placeholder="Name" />
  </div>
</div>

I'd hire some JavaScript code to do that. For example, in React when you iterate over an array, add another class to the parent component, which indicates it contains your children:

<div className={`parent ${hasKiddos ? 'has-kiddos' : ''}`}>
    {kiddos.map(kid => <div key={kid.id} />)}
</div>

And then simply:

.parent {
    color: #000;
}

.parent.has-kiddos {
    color: red;
}

In CSS, we can cascade to the properties down the hierarchy but not in the oppostite direction. To modify the parent style on child event, probably use jQuery.

$el.closest('.parent').css('prop','value');