This question already has answers here:
Is there a CSS parent selector?
(33 answers)
Closed 8 years ago.
I'm looking to make a selector which will select all elements if they have a specific child element. For example, select all <div> with a child <span>.
Possible?
Is it possible to select an element if it contains a specific child element?
Unfortunately not yet.
The CSS2 and CSS3 selector specifications do not allow for any sort of parent selection.
A Note About Specification Changes
This is a disclaimer about the accuracy of this post from this point onward. Parent selectors in CSS have been discussed for many years. As no consensus has been found, changes keep happening. I will attempt to keep this answer up-to-date, however be aware that there may be inaccuracies due to changes in the specifications.
An older "Selectors Level 4 Working Draft" described a feature which was the ability to specify the "subject" of a selector. This feature has been dropped and will not be available for CSS implementations.
The subject was going to be the element in the selector chain that would have styles applied to it.
Example HTML
<p><span>lorem</span> ipsum dolor sit amet</p>
<p>consecteture edipsing elit</p>
This selector would style the span element
p span {
color: red;
}
This selector would style the p element
!p span {
color: red;
}
A more recent "Selectors Level 4 Editor’s Draft" includes "The Relational Pseudo-class: :has()"
:has() would allow an author to select an element based on its contents. My understanding is it was chosen to provide compatibility with jQuery's custom :has() pseudo-selector*.
In any event, continuing the example from above, to select the p element that contains a span one could use:
p:has(span) {
color: red;
}
* This makes me wonder if jQuery had implemented selector subjects whether subjects would have remained in the specification.
Update December 2022 - Only Firefox is not supporting has()
The :has() pseudo-selector is proposed in the CSS Selectors 4 spec, and will address this use case once implemented.
To use it, we will write something like:
.foo > .bar:has(> .baz) { /* style here */ }
In a structure like:
<div class="foo">
<div class="bar">
<div class="baz">Baz!</div>
</div>
</div>
This CSS will target the .bar div - because it both has a parent .foo and from its position in the DOM, > .baz resolves to a valid element target.
Original Answer (left for historical purposes) - this portion is no longer accurate
For completeness, I wanted to point out that in the Selectors 4 specification (currently in proposal), this will become possible. Specifically, we will gain Subject Selectors, which will be used in the following format:
!div > span { /* style here */
The ! before the div selector indicates that it is the element to be styled, rather than the span. Unfortunately, no modern browsers (as of the time of this posting) have implemented this as part of their CSS support. There is, however, support via a JavaScript library called Sel, if you want to go down the path of exploration further.
I agree that it is not possible in general.
The only thing CSS3 can do (which helped in my case) is to select elements that have no children:
table td:empty
{
background-color: white;
}
Or have any children (including text):
table td:not(:empty)
{
background-color: white;
}
Related
This question already has answers here:
Can I combine :nth-child() or :nth-of-type() with an arbitrary selector?
(8 answers)
Closed 7 months ago.
I just realized I don't understand how :last-of-type pseudo-class works. A simple example: I have a table with last sticky column, I want to select all cells (tds) placed right before the last sticky cell (with a class ds-dt-sticky-cell).
table tr td:not(.ds-dt-sticky-cell):last-of-type {
background: red;
}
As expected, if I remove :last-of-type part, it selects all cells but sticky ones. In a DOM-tree everything looks good:
What am I doing wrong?
Short answer: what you're looking for is :last-of-class, which doesn't exist (quite yet).
The :last-of-type pseudo-class is based on :nth-child, which iterates through all children in a container and selects specific children by index. However, :last-of-type also takes into account the element's type, i.e. the HTML tag name (div, span, etc.).
None of these pseudo-classes, however, take into account any other part of your CSS selector. Class names, attribute selectors, etc., are not taken into account by :nth-child nor :last-of-type. For instance: you can select the last li within a container, but you cannot select the last thing of class "test".
li:last-of-type {
/* this matches on the last `li` in the list */
color: red;
}
li.test:last-of-type {
/* this doesn't match because it needs to be _both_:
* the last `li` in the list AND of class "test". */
color: blue;
}
<ul>
<li class="test">foo</li>
<li>bar</li>
</ul>
The CSS Selectors Level 4 specification adds a new feature for :nth-child in section 14.13.1:
The :nth-child(An+B [of S]? ) pseudo-class notation represents elements that are among An+Bth elements from the list composed of their inclusive siblings that match the selector list S, which is a <compound-selector-list> parsed as a forgiving selector list. If S is omitted, it defaults to *|*.
What this means is that, according to the level 4 spec, you should be able to write CSS like this to select by class name or other criteria:
li:nth-last-child(1 of .test) {
color: blue;
}
<ul>
<li class="test">foo</li>
<li>bar</li>
</ul>
Unfortunately, browser support isn't quite caught up on Selectors Level 4. At the moment, this example works in Safari, but not Firefox (bug report) nor Chrome (bug report). Browser support overview.
It's difficult to see from the screen grab why you need the last-of-type?
Wouldn't table tr td:not(.ds-dt-sticky-cell) do what you want? Or are there multiple .ds-dt-sticky-cell tds in each tr?
Or do you mean you want to target the last cell in each row - except for when it's .ds-dt-sticky-cell?
table tr td:last-child:not(.ds-dt-sticky-cell) { background: red; }
Here is the official documentation for the CSS3 :not() pseudo-class:
http://www.w3.org/TR/css3-selectors/#negation
and the proposed CSS Selectors Level 4 enhancement:
http://dev.w3.org/csswg/selectors4/#negation
I've been searching the implementation and browser support for :not(), but the only examples I found were with a single element or with a direct child of an element, e.g.:
div *:not(p) { color: red; }
The example above works when <p> is a direct child of <div>, but it does not work when <p> is a more distant descendant of <div>.
div :not(p) {
color: red;
}
<div>
<ul>
<li>This is red</li>
</ul>
<p>This is NOT</p>
<blockquote><p>This is red but is not supposed to be!</p></blockquote>
</div>
If the answer is in the official documentation above, then I didn't find/understand it. As I said, I have searched this site and the web but couldn't find any discussion about the support or lack thereof of :not() as grand-children of another element.
Is this supposed to work like I think it should?
Is this supposed to work like I think it should?
No, the behavior you're seeing is correct.
In your last example, although the <blockquote> contains a <p>, it's the <blockquote> itself that's matching *:not(p), as well as the condition that it must be a descendant of the <div>, which it is. The style is applied only to the <blockquote>, but it is then inherited by the <p> inside it.
The <p> element itself still counts against the negation, so the <p> itself is still being excluded from your selector. It's just inheriting the text color from its parent, the <blockquote> element.
Even if none of its relatively close ancestors matched the selector, you have elements like html and body to worry about as well — although you could probably just tack on a body selector in the very beginning:
body div...
This is why I often strongly advise against using the :not() selector for filtering descendants, especially when not qualified with a type selector (like div in your example). It doesn't work the way most people expect it to, and the use of inherited properties like color only serves to compound the problem, on top of making it even more confusing for authors. See my answers to these other questions for more examples:
Why doesn't this CSS :not() declaration filter down?
CSS negation pseudo-class :not() for parent/ancestor elements
The solution to the problem described is to simply apply a different color to <p> elements. You won't be able to simply exclude them with a selector because of inheritance:
/* Apply to div and let all its descendants inherit */
div {
color: red;
}
/* Remove it from div p */
div p {
color: black;
}
On Selectors Level 4: yes, :not() has indeed been enhanced to accept full complex selectors that contain combinators. Essentially, this means (once browsers begin implementing it) you will be able to write the following selector and have it do exactly what you want:
p:not(div p) {
color: red;
}
In case anyone is interested, this works in jQuery today.
The color is assigned to the blockquote, and is then inherited by the p.
:not(p) just makes it so that the styles are not directly applied. They are still inherited though.
I'm reading the book: CSS Mastery: Advanced Web Standards Solutions, and finding the css code inside is almost writed in this format:
elementName#idName
elementName.className
but, I'm used to write code ignoring element name with this format:
#idName
.className
so, I want to figure out what difference is between the two format.
Actually, I understand when should use type.class. And, I just want to find out the impact when I use type.class insead of only using .class when there is only one kind of tag here.
There must be some impact on performance.
Here's a real life scenario as when to use elementName and when to just use class or id name:
HTML:
<a class="blue">I'm blue and underline</a>
<span class"blue">I'm blue and bold</a>
CSS:
.blue {
color:blue //will make both <a> and <span> blue
}
a.blue {
text-decoration:underline // will make only the <a> tags underline
}
span.blue {
font-weight:bold //will make only the <span> tags bold
}
but remember when it comes to IDs you should not have duplicate IDs on your page anyway, this is more practical for classes
The difference between the two is that the first:
element.class
Is calling the element with that specific class.
And the second:
.class
Is calling all elements that contain this class
I think that the element inclusion in the selector is a holdover from days where some browsers required it (I think IE5 does, but I could be wrong). This is no longer necessary, and it does not make sense to include element selector for at least three reasons:
It slows the selector down since the element selector is slower than the other two -- especially id. Assuming selection is optimized so that fast selection is done first (e.g. the element with the matching id is found before the element selector is checked), there is still the additional step of checking the element selector.
It's not as extensible since you can't change the element without also having to change the selector. The implication is also that div.class would function differently than label.class, but I think that the class should be descriptive enough.
It changes the specificity of the selector. This could be very frustrating for some developers who may want to change <div class="foo"> from green to red:
div.foo { color: green; }
/* below is not applied since the above has higher specificity */
.foo { color: red; }
I've never heard an argument that supports type.class unless old browsers need to be supported.
There are tens of CSS rules I would like to be applied on a section of a page - this part is easy:
.generalStyles a,p,button,div.foo {
/* many styling rules here*/
}
However, when I mark a section of a page with class="generalStyles", I would like certain subsections not to inherit those styles, such as descendants of class="noGeneralStyles" (1). This should work with arbitrary nesting.
What I am looking for is a selector that could be translated into:
Inherit CSS rules if you are a descendant of .generalStyles, but not
when .noGeneralStyles is a closer parent
An interactive jsFiddle example can be found here
EDIT: The solution (if there is any) should not make any assumptions of inner HTML
(1) - the reason is there are way too many CSS rules to reset
You won't be able to limit or otherwise control inheritance chains using selectors alone, not even through combining :not() and descendant selectors for the reasons given here and here. You will have to provide an overriding rule for elements within .generalStyles .noGeneralStyles.
How about using direct descendant selectors? > means it will select button tag, which is direct child to an element having class noGeneralStyles or generalStyles
Demo
.noGeneralStyles > button {
color: black;
}
.generalStyles > button {
color: red;
}
This question already has answers here:
Is there a "previous sibling" selector?
(30 answers)
Closed 6 years ago.
Is there any way using pure CSS(3) to select an element that is a preceding sibling of an element with a particular class?
i.e.:
html:
<div id='element-to-find'></div>
<div id='box1'></div>
<!-- a bunch more DOM elements between here --->
<div id='box2'>
<div id='inner-box'></div>
</div>
css:
#box1{ /*some styling*/ }
#box2{ /*some styling*/ }
#box2.active .....
Now, when #box2 has the class active I want to select and do something to the style of #element-to-find. Is there anyway to accomplish this?
There were multiple proposals to CSSWG in www-style#w3.org mailing list as for previous-sibling combinator: my one (2012), another 1, 2 (2013).
Common answer by Tab Atkins is like "we already have subject indicator for this". For selecting descendants of previous sibling (which would be trivial with previous-sibling combinator, e.g. .example - UL > LI), he suggests to use :matches() functional pseudoclass, e.g. :matches(!UL + .example) > LI. Both subject indicator and :matches() are currently in draft state and cannot be used in real world yet.
So you should add a regular class to the element-to-find element or (much less desired if your active class is added not via JS) use JavaScript to emulate previous-sibling-combinator functionality.
Without knowing any more of your selectors, you could potentially use CSS's :not() selector.
div:not(#box1), div:not(#box2) {
/*some style here*/
}
I would just suggest giving your #element-to-find a class as well when you select box2 and have a style ready for it.