CSS rule is executed with and without :not() selector [duplicate] - css

This is driving me nuts:
HTML:
<div><h1>Hello World!</h1></div>
CSS:
*:not(div) h1 { color: #900; }
Doesn't this read, "Select all h1 elements that have an ancestor that is not a div element...?" Thus, "Hello World!" should not be coloured red, yet it still is.
For the above markup, adding the child combinator works:
*:not(div) > h1 { color: #900; }
But doesn't affect the h1 element if it is not a child of a div element. For example:
<div><article><h1>Hello World!</h1></article></div>
Which is why I'd like to indicate the h1 element as a descendant, not a child, of the div element. Anyone?

Doesn't this read, "Select all h1 elements that have an ancestor that is not a div element...?"
It does. But in a typical HTML document, every h1 has at least two ancestors that are not div elements — and those ancestors are none other than body and html.
This is the problem with trying to filter ancestors using :not(): it just doesn't work reliably, especially when the :not() is not being qualified by some other selector such as a type selector or a class selector, e.g. .foo:not(div). You'll have a much easier time simply applying styles to all h1 elements and overriding them with div h1.
In Selectors 4, :not() has been enhanced to accept full complex selectors containing combinators, including the descendant combinator. Whether this will be implemented in the fast profile (and thus CSS) remains to be tested and confirmed, but once it is implemented, then you will be able to use it to exclude elements with certain ancestors. Due to how selectors work, the negation has to be done on the element itself and not the ancestor in order to work reliably, and therefore the syntax will look a little different:
h1:not(div h1) { color: #900; }
Anyone who's familiar with jQuery will quickly point out that this selector works in jQuery today. This is one of a number of disparities between Selector 3's :not() and jQuery's :not(), which Selectors 4 seeks to rectify.

The <html> element is not a <div>. The <body> element is not a <div>.
So the condition "has an ancestor that is not a <div>" will be true for all elements.
Unless you can use the > (child) selector, I don't think you can do what you're trying to do - it doesn't really make sense. In your second example, <article> is not a div, so that matches *:not(div) too.

Related

CSS selector for elements of specified class that are not contained in element with another class [duplicate]

This is driving me nuts:
HTML:
<div><h1>Hello World!</h1></div>
CSS:
*:not(div) h1 { color: #900; }
Doesn't this read, "Select all h1 elements that have an ancestor that is not a div element...?" Thus, "Hello World!" should not be coloured red, yet it still is.
For the above markup, adding the child combinator works:
*:not(div) > h1 { color: #900; }
But doesn't affect the h1 element if it is not a child of a div element. For example:
<div><article><h1>Hello World!</h1></article></div>
Which is why I'd like to indicate the h1 element as a descendant, not a child, of the div element. Anyone?
Doesn't this read, "Select all h1 elements that have an ancestor that is not a div element...?"
It does. But in a typical HTML document, every h1 has at least two ancestors that are not div elements — and those ancestors are none other than body and html.
This is the problem with trying to filter ancestors using :not(): it just doesn't work reliably, especially when the :not() is not being qualified by some other selector such as a type selector or a class selector, e.g. .foo:not(div). You'll have a much easier time simply applying styles to all h1 elements and overriding them with div h1.
In Selectors 4, :not() has been enhanced to accept full complex selectors containing combinators, including the descendant combinator. Whether this will be implemented in the fast profile (and thus CSS) remains to be tested and confirmed, but once it is implemented, then you will be able to use it to exclude elements with certain ancestors. Due to how selectors work, the negation has to be done on the element itself and not the ancestor in order to work reliably, and therefore the syntax will look a little different:
h1:not(div h1) { color: #900; }
Anyone who's familiar with jQuery will quickly point out that this selector works in jQuery today. This is one of a number of disparities between Selector 3's :not() and jQuery's :not(), which Selectors 4 seeks to rectify.
The <html> element is not a <div>. The <body> element is not a <div>.
So the condition "has an ancestor that is not a <div>" will be true for all elements.
Unless you can use the > (child) selector, I don't think you can do what you're trying to do - it doesn't really make sense. In your second example, <article> is not a div, so that matches *:not(div) too.

Is the CSS :not() selector supposed to work with distant descendants?

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.

Overriding a class in CSS

There are already many questions related to this. But I'm still not clear. Also not sure if the title of the question is correct. Here's my problem:
What the below CSS code means?
#nav li { /*some cssA*/ }
#nav li.over { /*some cssB*/ }
#nav li a { /*some cssC*/ }
#nav li a:hover { /*some cssD*/ }
#nav li ul a span { /*some cssE*/ }
As per my understanding, please correct me if I am wrong:
Line 1: every li element within any element with id="nav" will have styling cssA
Line 2: When I put my cursor over every li element within any element with id="nav" will have styling cssB
Line 3: every a element within every li element within any element with id="nav" will have styling cssC
Line 4: When I hover every a element within every li element within any element with id="nav" will have styling cssD
Line 5: Every span element within every a element within every ul element within every li element within any element with id="nav" will have styling cssE. Also anyother ul or a element will not have this style untill unless the parent element has id="nav"
You are correct on all except .over, The "." represents a class. and "#" represents ID. But yeah, you've got the concept down.
Also, if you want to "Override" as the title says, you'll add
!important
to the end of any rules you want to take precedence over the others.
you can override the css by giving !important or you can give inline style.
priority of inline css is high then external css
All of the existing answers are correct, but there is a bit more to it than has been given already.
As has already been said, "li.over" is a combined selector - it will selector li elements that also have a class of "over". If you wanted to use different CSS properties or property values whilst the mouse is over (hovering over) the element then you use the pseudo class selector "li:hover". These are called pseudo class as you aren't selecting something that is part of the document, but based on the state of an element. There are also pseudo elements which again aren't in the document directly, but logical extensions of the document structure - for example first-child, first-of-type, fifth-of-type, odd items etc.
"#nav li ul a span" is a descendant selector, as you say it will select elements that are children (at any level) of each parent, so "#nav li" selects "li" elements contained within an item with ID "nav" - even several levels down.
If you want to select items that are direct children of the parent then you can use the ">" symbol. I.e. "#nav > li" will select li elements that are directly below any item with an ID of "nav", but not any li elements that are children of that element, or indeed elements below that.
Incidentally "#nav" is exactly equivalent to "*#nav" as it selects any element with the ID, you could also write "ul#nav" if you only wanted to select ul elements with the ID. This could in turn be combined with a class "ul#nav.bar" or even multiple classes "ul#nav.bar.touch".
Removing the space between the selectors like this combines them, so in the last case instead of looking for an item with class "touch" inside an item with class "bar" inside an item with ID "nav" inside a "ul" element, you are selecting a "ul" element with an ID of "nav" and both the classes "bar" and touch". An element like this-
<ul class="bar touch" id="nav">...</ul>
It is also possible to use attribute selectors, so if you wanted to select links which will open in a new window you could use "a[target=_blank]" - which selects based both on the presence of the attribute and the value - or if you wanted to select links with any href value you could use "a[href]". This simply selects all elements with this attribute.
On top of that you can even select items which are adjacent (next to) another element, if you wanted to select all paragraphs directly following an image then you would use "img + p" in your selector, or "p + img" if you wanted to select images directly following a paragraph. As always the last item in the selector is the one the styles are applied to.
It is generally considered good practice not to be overly specific with CSS selectors, as it makes your code much less re-usable. Unless you need to write "div.widget" just write ".widget" as the otherwise you'd not be able to create a "widget" using other elements, and it makes it much harder to override these properties later on in those cases you might need to.
To wrap up selectors, there's a good introduction to CSS selectors on MDN and Code School (paid course provider) also have a excellent online foundation course on CSS available for a very reasonable price which will go through selectors in some detail.
With regard to overriding classes, there are two further concepts you should understand - cascade order and specificity.
Given a HTML snippet of-
<div class="widget">
<p>
Some text you want to style
</p>
</div>
And the following CSS-
#widget p { color: yellow; }
p { color: blue; }
The color of the text would be yellow and not blue because the specificity of the first selector is greater (more specific) than the second. To understand this I suggest you have a play with a Specificity calculator and have a read of the Smashing Magazine tutorial on the subject.
In short though, inline styles trump all, and the more specific a selector the more likely it is to be applied in place of other selectors that would otherwise apply different property values. The value in the selector with the highest specificity score "wins", but other property values from selectors with lower specificity that do not clash will also still be applied to the element.
For example, altering our earlier CSS-
#widget p { color: yellow; }
p {
color: blue;
font-weight: bold;
}
The text will still be yellow, but will also be bold as there is no font-weight property given in the selector with higher specificity.
The last concept you should understand is what happens when two or more rules have identical specificity.
#widget p { color: yellow; }
#widget p {
color: blue;
font-weight: bold;
}
In this case our text is now blue as the second rule appears later in the stylesheet and thus overrides the first. If you have multiple stylesheets then the rules from the last stylesheet to appear in the document head will override rules with identical specificity.
In almost all cases you should use a more specific or the order of the selectors within the stylesheet in order to apply the right styles to the right element, and absolutely should not be routinely using the !important flag to achieve this unless absolutely necessary. See http://james.padolsey.com/usability/dont-use-important/ for a fuller explanation than I give here, but it rapidly becomes unmaintainable (what do you do when everything is "important") and it is also not accessible for users who may wish to override your styles in their user agent stylesheet (local to their browser) in order to help them read or use the page (increasing font size, contrast with background colour etc.)

What's the difference between `.class1.class2` and `.class1 .class2` CSS rule?

I have a table with some rows:
<table>
<tr class="even"><td>tr0</td></tr>
<tr><td>tr1</td></tr>
<tr class="even"><td>tr2</td></tr>
</table>
I have a CSS rule (rule1) for even rows:
.even{
background-color: blue;
}
I have another rule (rule2) for override the bgcolor of any row:
.override, .override.even{
background-color: green;
}
The weird thing is in IE9 all even rows (with no override class) are green!
Developer tools shows this for even rows:
In these two conditions IE do the job correctly:
If I rewrite rule2 like this:
.override, .override .even{ ... }
If I move rule2 above rule1:
.override, .override.even{ ... }
.even { ... }
Question is what's the difference between .override.even and .override .even?
EDIT:
Thanks for replies. Another question which I forgot to ask is why IE shows the even rows green?
Spacing in between class specifiers means a ascendant -> descendant relationship.
The rule:
.test .heading { font-weight: bold; }
Would apply to the <p> element here:
<span class="test"><p class="heading">Something</p></span>
The lack of space means that the element must have both classes for the rule to apply.
The rule:
.heading.major { color: blue; }
Would apply to the <p> element here:
<p class="heading major">Major heading</p>
Both answers are right, but they don't explain, why IE shows both rows green.
It's because IE has "standard" and "quirks" mode. To make multiple classes selectors work, you need to use proper DOCTYPE at the beginning of the file.
You are in "quirks" mode now and IE don't support multiple selectors, it sees only latest class. So it sees this and rows are green:
.even {
background-color: blue;
}
.override, .even {
background-color: green;
}
Put
<!DOCTYPE html>
(or another DOCTYPE) at the beginning of the file and both rows are going to be blue as expected.
See the W3C [CSS] Selector (Level 3) "Recommendation":
.override .even is two simple selectors separated by a space (which is the descendant combinator, CSS is whitespace-sensitive):
At times, authors may want selectors to describe an element that is the descendant of another element in the document tree (e.g., "an EM element that is contained within an H1 element"). Descendant combinators express such a relationship. A descendant combinator is whitespace that separates two sequences of simple selectors. A selector of the form "A B" represents an element B that is an arbitrary descendant of some ancestor element A.
This selector will match elements that have the class even if and only if there exists an ancestor -- not necessarily the parent! -- element with the class override. (Unlike characters in some movies, an element is never it's own ancestor ;-)
.override.even is a simple selector sequence:
A sequence of simple selectors is a chain of simple selectors that are not separated by a combinator. It always begins with a type selector or a universal selector. No other type selector or universal selector is allowed in the sequence.
A simple selector sequence is evaluated as the conjunction of the individual simple selectors applied to the same element: that is, it will only match elements with both the override and even classes applied.
Happy coding.
.override .even is interpreted as "some element with an 'override' class, with another element with a .even class nested within. It's basically the same as ul li, but applying to CSS classes.
override.even is interpreted as "some single element with BOTH override AND even classes".
<div class="class1">
<div class="class2">
<p>test1</p>
</div>
</div>
If this type coded added than use space between to class like .class1 .class2
<div class="class1 class2">
<p>test2</p>
</div>
If this type coded added than don't use space between to class like .class1.class2

Can I target a :before or :after pseudo-element with a sibling combinator?

Is there a reason why this CSS doesn't work?
http://jsfiddle.net/6v5BZ/
a[href^="http"]:after {
content:"";
width:10px;
height:10px;
display:inline-block;
background-color:red;
}
a[href^="http"] img ~ :after {
display:none;
}
.. on this HTML?
Test
<a href="http://google.com">
<img src="https://www.google.com/logos/classicplus.png">
</a>
The idea is to have a pseudo-element on matching anchor tags. But I do not want it to apply to anchor tags that wrap an image. And since I can't target anchors using something like a < img, I figured the maybe I could target the :after pseudo-element by finding an image that it's a sibling of.
Any insight would be greatly appreciated.
You can't target :after since it's content is not rendered in the DOM and it does not manipulate it - for this to work the DOM would have to be re-rendered and CSS can't manipulate it like this.
Check the specification for detailed understanding: http://www.w3.org/TR/CSS2/generate.html#propdef-content
Generated content does not alter the document tree. In particular, it
is not fed back to the document language processor (e.g., for
reparsing).
I suggest you use JavaScript to do the job for you.
You cannot use a combinator to target a pseudo-element relative to elements other than its generating element.
This is because they're pseudo-elements, not actual elements, and combinators only work by establishing relationships between actual elements. A pseudo-element, on the other hand, can only be applied to the subject of a selector (the rightmost compound selector), and this happens only after matching is processed on the real elements. In other words, matching is done first as though the pseudo-element wasn't there, then the pseudo-element, if it's indicated within the selector, is applied to each match.
In your code, the following selector:
a[href^="http"] img ~ :after
Does not actually look for an :after pseudo-element that comes after an img within the a, even though it appears that way as both are rendered as children of the a element.
It can be rewritten into the following:
a[href^="http"] img ~ *:after
Notice the * selector, which is implied. Similarly to how you can omit * before any other simple selectors for it to be implied, omitting * from a pseudo-element also makes it implied to be there. See the spec for details.
Now, even though it appears *:after should still match a:after (since a would match *), it still doesn't work that way. If you remove the :after pseudo-element from the selector:
a[href^="http"] img ~ *
You'll notice that the meaning of the selector changes entirely:
Select any element
that appears as a following sibling of an img
that is a descendant of an a (whose href starts with "http").
Since the img is the last child of the a element in your HTML, there are no following siblings to match, and therefore no :after pseudo-elements can be generated.
In the case of a :before or :after pseudo-element, one might think of matching the pseudo-element's generating element relative to the pseudo-element's "sibling", but as the OP has correctly pointed out, there is no parent selector, so they're out of luck there, too.

Resources