CSS :not selector without combining - css

I am trying to figure out how :not selector works. First of all I try this code
<!DOCTYPE html>
<html>
<head>
<style>
p {
color: #000000;
}
:not(p) {
color: #ff0000;
}
</style>
</head>
<body>
<h1>This is a heading</h1>
<p class="example">This is a paragraph.</p>
<p>This is another paragraph.</p>
<div>This is some text in a div element.</div>
</body>
</html>
It works as ı expect the paragraphs aren't styled and the text in the div and the heading are red. After that I am changing the part in the style tags to this:
<style>
:not(p) {
color: #ff0000;
}
</style>
This time it doesn't work as I expected. Although I want all the elements that are not paragraphs to be red all of them are displayed as red.
Furthermore I am changing the code between the style tags to this:
<style>
:not(p.example) {
color: #ff0000;
}
</style>
This time I am expecting the elements doesn't fit to "p.example" (h1, div and the second paragraph) to be red but none of the elements are affected.
What do I miss? Shouldn't the examples shown above select all the elements those don't fit to the argument selector? Is there a rule about not using the :not selector alone (e.g not as p:not or h1:not)?

Neither of the previous answers is entirely correct.
In your second case, merely specifying
:not(p)
colors everything red because it colors the body, and color is inherited.
You to NOT have to specify, as one answer claims,
body :not(p) {
color: #ff0000;
}
That is almost exactly equivalent to :not(p) (which means *:not(p)). Nor do you have to specify any other parent such as .main as another answer claims.
The third example fails because the argument to :not is not a simple selector. The syntax you gave seems to be trying to do is to select everything that is not a p with the example class. As another respondent pointed out, what you probably meant was everything that is a p but without the example class, for which p:not(.example) is correct.
To select elements which are not A and not B (in other words not (A or B), just do
:not(A):not(B)
For example,
:not(h1):not(p)
which in this example will apply to the body and the div. A more realistic example would be to select p's other than those with either of two classes:
p:not(.class1):not(.class2)

The selector :not(p) matches all elements except p elements. This includes the body element. When your only style sheet is :not(p) { color: #ff0000; }, you thus set all content color red, since the p elements inherit color from their parents (here p) when no color is set on them directly.
If you want to set the color of content to red except for p elements and their descendants, you thus need to be more explicit. A simple way, assuming that this all you want to color, is to set the overall color to red and then override it for p elements, letting inner elements inherit color:
body { color: red }
p { color: black }
The reason why :not(p.example) does not work at all is that the operand of :not must be a simple selector, namely a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class, but not any combination of these; and p.example isn’t simple.
You could use the combined selector :not(p):not(.example), which matches any element except p elements in class example. And this is probably what you want. But the rule won’t work the way want, since here, too, the selector matches the body element, among other things, and its color gets inherited by the only element that has not got color specified for it directly. So even in this case, you would need to think otherwise, setting e.g.
body { color: red }
p.example { color: black }

After #abhitalks comments/feedback. In your first example is nothing wrong, just is related to only inherited properties which will not work. color is inherited, but border is not:
Take a look here Full property table
:not(p) {
color: #f00;
border: 1px solid gray;
}
<h1>This is a heading</h1>
<p class="example">This is a paragraph.</p>
<p>This is another paragraph.</p>
<div>This is some text in a div element.</div>
In you second example:
Selectors level 3 does not allow anything more than a single simple
selector within a :not() pseudo-class.
You can change it to:
body :not(.example) {
color: #ff0000;
}
<h1>This is a heading</h1>
<p class="example">This is a paragraph.</p>
<p>This is another paragraph.</p>
<div>This is some text in a div element.</div>

When you use :not selector, you should mentioned some parent. Based on that parent only it will work. Otherwise it will select all the elements only.
<div class="main">
<h1>This is a heading</h1>
<p class="example">This is a paragraph.</p>
<p>This is another paragraph.</p>
<div>This is some text in a div element.</div>
</div>
CSS:
.main :not(p) {
color: #ff0000;
}
Also if you don't want to select particular element using :not selector you need to use like below.
p:not(.example)
{
color:green;
}
FIDDLE DEMO

Related

Different behavior for pseudo-class with space and without space

This issue is related to CSS pseudo-class. I refer to :last-child just for example, I suppose it happens to all other pseudo-class too.
Given I have following simple HTML:
<body>
<p>Paragraph1</p>
<p>Paragraph2</p>
</body>
I add following CSS:
body:last-child{
color:red;
}
<body>
<p>Paragraph1</p>
<p>Paragraph2</p>
</body>
Without space both paragraphs will be marked as red
When I will set space between .body and :last-child, only second paragraph will be marked as red - that happens in Google Chrome, I see snippet tool doesn't mark any paragraph with red.
body: last-child{
color:red;
}
<body>
<p>Paragraph1</p>
<p>Paragraph2</p>
</body>
Question: Could anyone help me understand why this happens? Maybe anything to read more on behaviour with space and without space for pseudo-class?
It's last paragraph not last body.
So, just do this:
body p:last-child{
color: red;
}
Space separates the next level of elements for css selector to work.
pseudo-element should always work without Space in between of element and colon .eg
body p:last-child{ color:red; }
1. Without spacing
body:last-child {
color: red;
}
<body>
<p>Paragraph1</p>
<p>Paragraph2</p>
</body>
In the above code, all the p elements are red because color: red is applied to the body and is applied to the child elements as well. body:last-child, here :last-child is w.r.t to the parent and does not mean last child of body element.
2. With spacing
body: last-child{
color:red;
}
The above is invalid syntax and does not apply styling. You can validate your CSS: W3C CSS Validator
3. Solution:
body p:last-child { /* Select the paragraph which is last inside body */
color: red;
}
Avoid using this in SO snippets as the child selectors will be difficult to style. <link> and <script> is added/appended to the markup and disrupts the child selector.
With body:last-child, you target the last body (and there is only one). So everything within the body will be colored red.
The body: last-child doesn't work, because it is invalid.
What you are looking for is body p:last-child.

nth-child doesn't work when the tag SPAN is on

Here is my code
<span></span>
<div class='box'>title</div>
<style>div.box:nth-child(1) { color: red; }</style>
It works when I delete the span tag or any other tag which is over the box, but not when I leave it as is. Why is it so?
Use :nth-of-type .
Basically :nth-child counts ALL the siblings. Regardless of type of element. However :nth-of-type takes into account the element selected.
Because the div is now the second child. Use :nth-of-type(n) instead.
<style>
div.box:nth-of-type(1) { color: red; }
</style>
That will select the first div

css :not(), selectors and selecting descendants

Let's say I have :
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test for :not</title>
<link rel="stylesheet" type="text/css" href="Test.css" />
</head>
<body>
<div class="a">
<p class="para">This line should be green.</p>
</div>
<div class="a">
<p class="para">This line should also be green.</p>
<div class="ds">
<p class="para">This is another line that should be yellow</p>
</div>
</div>
</body>
</html>
I want to select all the elements with class="para" but exclude those that are descendants of those elements that have a class="ds". I have this CSS:
.ds { color: grey; border-style:solid; border-width:5px;}
.para {color:yellow;}
.para:not(.ds .para) {color:green; border-style:solid; border-width:5px;} //not working
So I assume I can only have simple selectors as part of :not(S), I can't have :not (X Y). I am running in both Chrome (18.0.1025.162 m) and Firefox (10). Any ideas?
Please note: That the query is part of a bigger issue, I have some code (in gwt) that is selecting a list of elements (e.g. with class="para") from the DOM. However, I have found a bug that requires the exclusion of elements that are descendants of a particular set of elements (e.g those with a class="ds").
The spec says that you can have any simple selector inside :not, where
A simple selector is either a type selector, universal selector,
attribute selector, class selector, ID selector, or pseudo-class.
So yes, you can't have a descendant selector :not(X Y). There is also the problem that when using the descendant selector you can only express positives ("when X's ancestors include a Y") and not negatives ("when X's ancestors do not include a Y");
The most practical solution would be to reverse the CSS logic so that the negative you want to express becomes a positive:
.ds .para { background:gold; }
.para { background: green }
See it in action.
Elements with class "para" excluding those that are immediate children of elements with class "ds" is:
*:not(.ds) > .para
I think you may be approaching it in the wrong way. Normal .para matches are green, and ones in .ds are yellow. To be sure, with the way you have it you would then need to remove the border once more, but that's not a problem.
.ds { color: grey; border-style:solid; border-width:5px;}
.para {color:green; border-style:solid; border-width:5px;}
.ds .para {color:yellow; border-style: none; }
This fits with what I see as the natural way of interpreting the formatting.

how can I compound css selectors together

is it possible to use a :not() selector with a :nth-of-type(1) selector?
i.e.
I want to select the first that doesn't have the title "something"
<html>
<head>
<style type="text/css">
p
{
color:#000000;
}
p:not([title=something]):nth-of-type(1)
{
color:#ff0000;
}
</style>
</head>
<body>
<h1>This is a heading</h1>
<p title="something">This is a paragraph.</p>
<p>This is another paragraph.</p>
<p>This is another paragraph.</p>
<div>This is some text in a div element.</div>
</body>
</html>
The nth-of-type is acting on the original selector (p), it's not acting on the result of p:not([title=something]).
p:not([title=something]):nth-of-type(1)
This is saying, find the <p> without a title of "someting" that is also the 1st <p> on the page. This doesn't find any elements as the 1st <p> has the title "something".
What you want is the 1st <p> that doesn't contain the title "something". I don't know if CSS has a good way of doing that.
If you're willing to use jQuery, you can use do this:
$('p:not([title="something"]):eq(0)')
or:
$('p').not('[title="something"]').eq(0)
The problem is that the nth-of-type pseudo-class is defined as:
[nth-of-type] matches elements on the basis of their positions within a parent element’s list of child elements.
So the pseudo-class :nth-of-type(1) is limiting your selection to the p child at position 1.
Your pseudo-class not([title=something]) is limiting your selection to the p elements without the attribute/value title='something', just as you suspect.
The two selectors together are resulting in no elements because the p child at position 1 has title='something'.
For a better understanding, try the following:
p:nth-of-type(1) { color: red; }
p:not([title=something]) { text-decoration:underline; }
More information: Pseudo-classes, nth-of-type
As mentioned by the other answers, :nth-of-type() only refers to the element type, which in this case is p. The selector p:not([type=something]):nth-of-type(1) simply means a p element that is :not([type=something]) and is also the first p.
Anyway, what you're asking can be done in pure CSS using the general sibling selector, but may involve unnecessarily verbose and repetitive selectors:
p:not([title=something]) ~ p:not([title=something])
{
color:#000000;
}
p:not([title=something])
{
color:#ff0000;
}
If you just want to apply this to p elements without a title attribute, you can shorten your selectors a little:
p:not([title]) ~ p:not([title])
{
color:#000000;
}
p:not([title])
{
color:#ff0000;
}
I came up with this technique for use with classes first, which I describe in greater detail here, but it can be applied to a number of things, including attributes, for which I have another example here.

How to skip first child?

<div id="main">
<p> one </p>
<p> two </p>
<p> three </p>
<p> four </p>
<p> five </p>
<div>
I don't want to apply css on first <p>One</p>
p {color:red}
I need just opposite of :first-child.
With the negation pseudo-class:
p:not(:first-child) { color: red; }
Browser support is very strong now, but alternatives include:
p { color: red; }
p:first-child { color: black; }
and:
* + p { color: red; }
Quentin's :not() solution works great for modern browsers:
p:not(:first-child) { color: red; }
His alternative for older browsers also works well, except it makes use of an overriding rule for the first child. It's not required, however...
You can simply use a sibling selector to apply the same rule as the one above, without the need to override it for p:first-child. Either one of these rules will work:
The adjacent sibling selector, which matches any p that comes directly after a p:
p + p { color: red; }
The general sibling selector, which matches any p that comes anywhere after a p:
p ~ p { color: red; }
Both combinators work identically here; the subtle differences between them only apply when you have other elements in the mix. Refer to the links provided for details.
I think :nth-child() will do the trick.
p:nth-child(n+2){
background-color:red;
}
This styles all of the p tags except for the first because it starts on the 2nd child. You could then style the first p tag separately with p:first-child.
Works everytime and doesn't need undoing:
p + p {
/* do 15 special things */
}
It takes every P that was preceded by a P. Don't set a property to undo it later. You should only add, if you can help it, not subtract.
You can also use "tilde" ( ~ ) operator
<!DOCTYPE html>
<html>
<head>
<style>
p ~ p {
background:#ff0000;
}
</style>
</head>
<body>
<h1>This is a heading</h1>
<p>The first paragraph.</p>
<p>The second paragraph.</p>
<p>The third paragraph.</p>
<p>The fourth paragraph.</p>
</body>
</html>
Here is the JSFiddle demo http://jsfiddle.net/RpfLa/344/
Did a quick test on FF 17, Chrome 23, Safari 5.1, IE9, IE1-8 on compaitbility mode

Resources