Apply CSS styles to an element depending on its child elements [duplicate]
Asked Answered
G

4

263

Is it possible to define a CSS style for an element, that is only applied if the matching element contains a specific element (as the direct child item)?

I think this is best explained using an example.

Note: I'm trying to style the parent element, depending on what child elements it contains.

<style>
  /* note this is invalid syntax. I'm using the non-existing
   ":containing" pseudo-class to show what I want to achieve. */
  div:containing div.a { border: solid 3px red; }
  div:containing div.b { border: solid 3px blue; }
</style>

<!-- the following div should have a red border because
     if contains a div with class="a" -->
<div>
  <div class="a"></div>
</div>

<!-- the following div should have a blue border -->
<div>
  <div class="b"></div>
</div>

Note 2: I know I can achieve this using javascript, but I just wondered whether this is possible using some unknown (to me) CSS features.

Geopolitics answered 24/2, 2010 at 14:3 Comment(4)
You might want to update the question to state, perhaps with blinking bold text, that you're trying to style the PARENT div, not its children. I know that info is in the question itself, but unless you want to get a ton of incorrect answers it's probably worth the effort.Tolbutamide
Thanks @Seth. I tried to improve the question title and text. Please edit the question if you think it still unclear.Geopolitics
This is the perfect example of why this type of support in CSS would be ideal: ol < li:nth-child(n+10) { margin-left: 2rem; } ol < li:nth-child(n+100) { margin-left: 3rem; } ol < li:nth-child(n+1000) { margin-left: 4rem; } In an ideal world this would increase the margin of the ol dependent on the number of li children in contained so that the margin on the left would only be as wide as it needed to be.Mumbletypeg
Actually this feature is in progress with :has selector - bkardell.com/blog/canihas.htmlSelfcentered
A
188

The syntax for that is:

div:has(div.a) { border: solid 3px red; }
div:has(div.b) { border: solid 3px blue; }

As far as I'm aware, styling a parent element based on the child element is not an available feature of CSS. You'll likely need scripting for this.

It'd be wonderful if you could do something like div[div.a] or div:containing[div.a] as you said, but this isn't possible.

You may want to consider looking at jQuery. Its selectors work very well with 'containing' types. You can select the div, based on its child contents and then apply a CSS class to the parent all in one line.

If you use jQuery, something along the lines of this would may work (untested but the theory is there):

$('div:has(div.a)').css('border', '1px solid red');

or

$('div:has(div.a)').addClass('redBorder');

combined with a CSS class:

.redBorder
{
    border: 1px solid red;
}

Here's the documentation for the jQuery "has" selector.

Aquileia answered 24/2, 2010 at 14:13 Comment(5)
Side note: for better performance, jQuery doc page for :has selector advises to use .has() method (api.jquery.com/has) => applied to current question it would give for example $('div').has('div.a').css('border', '1px solid red');Plott
For this to work one would have to use mutation observer, to check wether the child changed it's state...Rubbico
This doesn't truly answer the question which is "Is there a way to do this with CSS". It clearly states: "I know I can achieve this using javascript, but I just wondered whether this is possible using some unknown (to me) CSS features."Blatant
developer.mozilla.org/en-US/docs/Web/CSS/:has, I think this :has selector can work but it's in draft version and no browser supports it.Gilemette
As of October 2022, it's supported in Chrome and Edge, but not Firefox unless the user messes with about:configGearldinegearshift
K
82

Basically, no. The following would be what you were after in theory:

div.a < div { border: solid 3px red; }

Unfortunately it doesn't exist.

There are a few write-ups along the lines of "why the hell not". A well fleshed out one by Shaun Inman is pretty good:

http://www.shauninman.com/archive/2008/05/05/css_qualified_selectors

Update. Many years later, :has has arrived, browser support is increasing.

https://developer.mozilla.org/en-US/docs/Web/CSS/:has

12 years is a long time.

Kutaisi answered 24/2, 2010 at 14:19 Comment(7)
just an update 8 years later: there is still no support for this selector method.Kenwood
There is a working draft for this feature in the form of a :has() pseudo-class, but we'll only get to use it in CSS4. As of now (late 2019), JS is still the only way to achieve this functionality.Tyrant
I believe this won't enable css styles, it will still need javascript to use the selector. Unless this has changed?Kutaisi
9 years and do they think this feature is needless?Dinnie
11 years and still I and so many others are looking for a solution!Anagoge
12 years now and a quick note: there will be never a CSS4. css-tricks.com/css4Vulgate
^ Not even a year later, and while there may never be a CSS4, CSS using :has() is now supported in every major desktop browser to some degree (Gecko still has some feature gaps and requires an experimental preference setting to enable it), and on mobile devices in the Safari, Chrome, Android-builtin, and Opera browsers.Albuminoid
A
1

On top of @kp's answer:

I'm dealing with this and in my case, I have to show a child element and correct the height of the parent object accordingly (auto-sizing is not working in a bootstrap header for some reason I don't have time to debug).

But instead of using javascript to modify the parent, I think I'll dynamically add a CSS class to the parent and CSS-selectively show the children accordingly. This will maintain the decisions in the logic and not based on a CSS state.

tl;dr; apply the a and b styles to the parent <div>, not the child (of course, not everyone will be able to do this. i.e. Angular components making decisions of their own).

<style>
  .parent            { height: 50px; }
  .parent div        { display: none; }
  .with-children     { height: 100px; }
  .with-children div { display: block; }
</style>

<div class="parent">
  <div>child</div>
</div>

<script>
  // to show the children
  $('.parent').addClass('with-children');
</script>
Asti answered 27/7, 2017 at 16:43 Comment(0)
F
0

In my case, I had to change the cell padding of an element that contained an input checkbox for a table that's being dynamically rendered with DataTables:

<td class="dt-center">
    <input class="a" name="constCheck" type="checkbox" checked="">
</td>

After implementing the following line code within the initComplete function I was able to produce the correct padding, which fixed the rows from being displayed with an abnormally large height

 $('tbody td:has(input.a)').css('padding', '0px');

Now, you can see that the correct styles are being applied to the parent element:

<td class=" dt-center" style="padding: 0px;">
    <input class="a" name="constCheck" type="checkbox" checked="">
</td>

Essentially, this answer is an extension of @KP's answer, but the more collaboration of implementing this the better. In summation, I hope this helps someone else because it works! Lastly, thank you so much @KP for leading me in the right direction!

Firkin answered 21/12, 2019 at 0:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.