views:

13174

answers:

6

Is there a way to select a parent element based on the class of a child element in the class? The example that is relevant to me relating to HTML output by a nice menu plugin for http://drupal.org. The output renders like this:

<ul class="menu">  
    <li>  
        <a class="active">Active Page</a>  
    </li>  
    <li>    
        <a>Some Other Page</a>  
    </li>  
</ul>

My question is whether or not it is possible to apply a style to the list item that contains the anchor with the active class on it. Obviously, I'd prefer that the list item be marked as active, but I don't have control of the code that gets produced. I could perform this sort of thing using javascript (JQuery springs to mind), but I was wondering if there is a way to do this using CSS selectors.

Just to be clear, I want to apply a style to the list item, not the anchor.

+8  A: 

Unfortunately, there's no way to do that with CSS.

It's not very difficult with JavaScript though. For example, if you're using jQuery:

$('.active').parent().get(0); // This would be the <a>'s parent <li>.
Dave Ward
+15  A: 

According to Wikipedia:

Selectors are unable to ascend

CSS offers no way to select a parent or ancestor of element that satisfies certain criteria. A more advanced selector scheme (such as XPath) would enable more sophisticated stylesheets. However, the major reasons for the CSS Working Group rejecting proposals for parent selectors are related to browser performance and incremental rendering issues.

And for anyone searching SO in future, this might also be referred to as an ancestor selector.

Sam Hasler
+2  A: 

The Solution: CSS Pre-Selection.

The reason W3C won't implement this the way most of us have envisioned it is because of the potential for circular references and similar performance and stability issues. However, the method I am calling "pre-selection" solves this problem by preserving top-down-only selection matching, while still affording developers greater control over styling. To use the OP's example...

Problematic:

.menu a.active < li { ... }

Safe:

.menu <li> a.active { ... }

In the former case, I could cause real problems in a web browser with something sinister like:

.menu a < *

But in the latter case, there is a guaranteed termination point, the browser simply is instructed to buffer all the "LI" matches and strip out the ones that don't match the rest of the selection (i.e., which don't contain an "A" tag with the "active" class applied).

Disclaimer: Perhaps I should clarify that this is a suggestion to members of the W3C, not to the Original Poster or others who read this. The "CSS Preselection" feature is something I made up and is NOT currently a part of any CSS specification I'm aware of, official or otherwise.
If I remember correctly, CSS is determined right - left, and so I think it would be pretty simple for them to rule out circular references.
path411
+1  A: 

I had the same problem with Drupal. Given the limitations of CSS, the way to get this working is to add the "active" class to the parent elements when the menu HTML is generated. There's a good discussion of this at http://drupal.org/node/219804, the upshot of which is that this functionality has been rolled in to version 6.x-2.x of the nicemenus module. As this is still in development, I've backported the patch to 6.x-1.3 at http://drupal.org/node/465738 so that I can continue to use the production-ready version of the module.

Mark B
+1  A: 

Late to the party again but for what it's worth it is possible using jQuery to be a little more succinct. 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)")
David Clarke
+1  A: 

Hi all,

In addition to very helpful answers given above, I found it useful to look at a detailed description of css selectors, in the following address: http://www.w3.org/TR/CSS2/selector.html

Hope this helps

green-i