Why doesn't css :not work in some cases? - html

Why does the :not selector not work at all in this case:
a {
color:red;
}
div a:not(.special a) {
color: green;
}
In, for example:
<div>
<span>hellolink</span>
</div>
<div class="special">
<span>hellolink</span>
</div>
<p>
something else
</p>
Demo: https://jsfiddle.net/eguecrvz/

:not() currently doesn't allow combinators or any more than one simple selector (such as .special or a) as an argument. A future specification will expand :not() to accept any number of complex selectors, and once browsers support it your selector div a:not(.special a) will work exactly as intended.
In the meantime, it is not possible to write a selector for "an a element that does not have a .special ancestor element." You will need to override with an additional .special a selector in your rule that applies to a elements in general:
a, .special a {
color:red;
}
div a {
color: green;
}
The additional specificity of .special a will ensure that it overrides div a, but if specificity is a problem you will need to rearrange your rulesets.

special is class of div not anchor.
Change css like:
div:not(.special) a{
color: green;
}
Fiddle
Edit:
If you want all link green except .special the do like:
a {
color:green;
}
.special a{
color: red;
}
Updated Fiddle

Why doesn't css :not work in some cases?
div a:not(.special a) {
color: green
}
Because the negation pseudo-class (:not) only takes a simple selector as an argument.
Your argument (.special a) represents a descendant selector which does not qualify.
6.6.7. The negation
pseudo-class
The negation pseudo-class, :not(X), is a functional notation taking
a simple selector (excluding the negation pseudo-class itself) as an
argument. It represents an element that is not represented by its
argument.
What is a simple selector?
4. Selector syntax
A simple selector is either a type selector, universal selector,
attribute selector, class selector, ID selector, or pseudo-class.

Related

CSS not() with attribute selector doesn't seem to work

I have a very simple selector that works, but when adding it to a :not() it no longer seems to recognize it.
h2:not([random-attribute~="value"] h2){
color: red;
}
[random-attribute~="value"] h2{
color: blue;
}
<div class="content">
<h2>Same valid selector, not working</h2>
<div random-attribute="value">
<h2>Valid selector turned blue.</h2>
</div>
</div>
From what I understand, if you put a valid selector inside the not() you will get any h2 element that is not whatever is inside the parenthesis. This is intuitive.
What isn't intuitive, is that the selector within the not() is valid and works when used alone, but when added to the not() it doesn't seem to work.
Is this not a valid way to write this?
You need to style all h2 element that are descendants of elements that are not [random-attribute~="value"] then style h2 that are.
It doesn't hurt to qualify the selector with a direct child combinator too.
Like so:
*:not([random-attribute~="value"]) > h2 {
color: red;
}
[random-attribute~="value"] > h2 {
color: blue;
}
<div class="content">
<h2>Same valid selector, not working</h2>
<div random-attribute="value">
<h2>Valid selector turned blue.</h2>
</div>
</div>
<h2>some other heading</h2>
You have the syntax wrong for ([random-attribute~="value"] h2) It should just be ([random-attribute~="value"]). See below:
h2:not([random-attribute~="value"]){
color: red;
}
[random-attribute~="value"] h2{
color: blue;
}
<div class="content">
<h2>Same valid selector, not working</h2>
<div random-attribute="value">
<h2>Valid selector turned blue.</h2>
</div>
</div>
You are only supposed to put the given attribute in :not(), not the actual element.
In Selectors Level 3, :not only supports a simple selector argument. That will probably change in Selectors Level 4, but browsers don't support it yet.
The negation pseudo-class, :not(), is a functional pseudo-class
taking a selector list as an argument. It represents an element that
is not represented by its argument.
Note: In Selectors Level 3, only a single simple selector was allowed
as the argument to :not().
Meanwhile, you can rewrite
h2:not([random-attribute~="value"] h2)
as
:root:not([random-attribute~="value"]) > h2,
:root:not([random-attribute~="value"]) > :not([random-attribute~="value"]) > h2,
:root:not([random-attribute~="value"]) > :not([random-attribute~="value"]) > :not([random-attribute~="value"]) > h2
/* ... repeat until you get deep enough */
However, instead of using complicated selectors like that, in CSS it's more natural to let the cascade pick the most specific styles. As kristóf baján recommends, you don't even need :not:
h2 {
/* Default styles */
}
[random-attribute~="value"] h2 {
/* Overriding styles */
}
I think you are making your job a little too complicated... :)
You should just use:
[random-attribute="value"] h2{
...
}
h2 {
...
}
This should solve your problem. The reason behind the fact that it is not working as YOU would expect it to is that the selector inside the not operator is supposed to extend the clarification of the element and not its parent.

Does the :not pseudo class increase the specificity of a selector?

I have read on css tricks that :not should not add additional specificity. But it looks like it does?
https://css-tricks.com/almanac/selectors/n/not/
The specificity of the :not pseudo class is the specificity of its argument. The :not() pseudo class does not add to the selector specificity, unlike other pseudo-classes.
Or am I missing something?
.red:not(.blue) {
background: blue;
}
.red {
height: 100px;
width: 100px;
background: red;
}
<div class="red">
</div>
Yes, it adds the specificity of its argument. Look at the first sentence:
The specificity of the :not pseudo class is the specificity of its argument. The :not() pseudo class does not add to the selector specificity, unlike other pseudo-classes.
So the specificity of .red:not(.blue) is equal to that of .red.blue — 2 class selectors, or (0, 2, 0), making it more specific than .red on its own. What the second sentence means is that the :not() itself does not contribute the additional specificity of a pseudo-class to make it (0, 3, 0), like the :hover in .red.blue:hover does for example.
The :not selector don't have it's own specificity, however the selector inside :not() do have.
From MDN
Selector Types
The following list of selector types is by increasing specificity:
Type selectors (e.g., h1) and pseudo-elements (e.g., :before).
Class selectors (e.g., .example), attributes selectors (e.g., [type="radio"]) and pseudo-classes (e.g., :hover).
ID selectors (e.g., #example).
Universal selector (*), combinators (+, >, ~, ' ') and negation pseudo-class (:not()) have no effect on specificity. (The selectors declared inside :not() do, however.)
As you're having the rule .red:not(.blue) and the element <div class="red"> don't have the class blue, the rule is applied.
.red:not(.blue) {
background: blue;
}
.red {
height: 100px;
width: 100px;
background: red;
}
div {
background: green;
width: 50px;
height: 50px;
margin: 10px;
}
<div></div>
<div class="red"></div>
<div class="blue"></div>

CSS Sibling selector doesn't work inside :not()

I know that with pure CSS it's impossible to select previous siblings of the element. But I try to fool browser with a complex selector.
Please see this jsFiddle. It contains several CSS rules that work fine except 2 of them:
//set border color to white for all elements before .selected and .selected itself
div:not(.selected ~ div) {
border-color: #fff;
}
//set border color to green for the element previous to .selected
div:not(.selected ~ div):nth-last-child(2) {
border-color: #0f0;
}
But seems that inside :not() sibling selector ~ doesn't work.
So there're 2 questions:
Is it expected that ~ doesn't work inside :not()?
Is there any work-around for such case?
EDIT:
The final idea is to make a nice hover effect with pure CSS like:
The hovered image is simply scaled, image to right of it could be found and styled easily but the left one... The example with divs is just an example.
:not() pseudo-class could not contain sibling selector.
http://dev.w3.org/csswg/selectors3/#negation
The negation pseudo-class, :not(X), is a functional notation taking a simple selector (excluding the negation pseudo-class itself) as an argument.
http://dev.w3.org/csswg/selectors3/#simple-selectors-dfn
A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
If you want to :
set border color to white for all elements before .selected and
.selected itself
I would suggest to default the border color to white and change it after .selected :
div {
display: inline-block;
border: 1px solid #fff;
width: 30px;
}
div.selected ~ div {
border-color: #000;
}
<div>A</div>
<div>B</div>
<div class="selected">C</div>
<div>D</div>
<div>E</div>
<div>F</div>
<div>G</div>
For the second rule :
set border color to green for the element previous to .selected
If you know wich one will be selected in advance, you can target the element before with nth-child() otherwise you will need some JS to select it.
An other approach if the .selected class is dynamicaly added would be to use the same mechanism (PHP, JS or other) to give a class to the privious element at the same time and apply CSS to that class.
It is possible since CSS Level 4.
https://www.w3.org/TR/selectors-4/
The negation pseudo-class, :not(), is a functional pseudo-class taking a selector list as an argument.
Also it is changed from :not( <selector># ) to :not( <complex-selector-list> ) in https://developer.mozilla.org/en-US/docs/Web/CSS/:not#syntax in November 2018.
See browser compatibility for "Selector list argument" in https://developer.mozilla.org/en-US/docs/Web/CSS/:not#browser_compatibility.

css :not selector to target everything but a condition

http://jsfiddle.net/m7qLdstp/1/
<style>
:not(div p), p{
color: red
}
</style>
<p>This is a paragraph that should be red.</p>
<div><p>This is a paragraph that should not be red.</p></div>
Is it possible to use the css :not selector to (in this case) turn all <p> color red, except for any <p> instead a <div>?
I ran a few different variations on jsfiddle but cannot get it to work?!
The following will change the color of all <p> elements that are not direct descendants of a <div>:
:not(div) > p{
color: red;
}
Demo fiddle
You could just target them separately
p{
color: red
}
div p{color:black}
fiddle
it works because div p is more specific than p
According to CSS-Tricks, :not() selector can take only a "simple selector", defined as:
a Type Selector, Universal Selector, Attribute Selector, Class Selector, ID Selector, or Pseudo Class Selector
but:
may not contain additonal selectors or any pseudo-element selectors.
However, as other answers suggest, there are ways you could work around this issue and accomplish the behavior at least in this example case and other simple cases.

How to use first-child?

I would like to select the first div called "aProduct" but I'm a bit confused on how to do this. I already tried this:
<div id="kasticketProducts">
<div class="aProductHeader"></div>
<div class="aProduct"></div>
<div class="aProductHeader"></div>
<div class="aProduct"></div>
</div>
This is my current CSS:
#kasticketProducts:first-child .aProduct {
margin-top: 30px;
background: red;
}
#kasticketProducts:first-child .aProduct
Using above css means first it'll search for id with kasticketproducts in that first-child, here first child refer to aProductHeader from here you are trying to search aProduct but it is not there.
Actually from DOM hierarchy aProduct class div is at second child this will be referred in css as nth-child(2) here and no need of again .aProduct .So the final solution for this is write as #kasticketProducts div:nth-child(2)
First, whats the difference?
From MDN :
:first-child()
The :first-child CSS pseudo-class represents any element that is the first child element of its parent.
:first-of-type()
The :first-of-type CSS pseudo-class represents the first sibling of its type in the list of children of its parent element.
So inshort, :first-child() is somewhat a loose pseudo selector compared to :first-of-type()
Unfortunately :first-child or :first-of-type doesn't respect classes or ids, they are only concerned with the DOM elements. So if you do something like, will fail
#kasticketproducts div.aProduct:first-of-type {
color: red;
}
So in this case the best you can do with CSS is use :nth-of-type() with 2 as a value, now obviously it will fail if your element doesn't have a class of aProduct
#kasticketproducts div:nth-of-type(2) {
color: red;
}
Demo
OR
you can use adjacent selector with :first-of-type()
#kasticketproducts div:first-of-type + div {
color: red;
}
Demo
Second solution is MORE COMPATIBLE as far as IE is concerned
DEMO
Code is not working because aProductHeader class is before first occurrence of aProduct class.
See demo.
You can't target the first element of a class, but you can target the elements that come after, so you can set the styles on all the aProduct elements and then override it on all aProduct that comes after the first one using the ~ opreator:
#kasticketproducts .aProduct {
margin-top: 30px;
background: red;
}
#kasticketproducts .aProduct ~ .aProduct {
margin-top: 0;
background: none;
}
Demo: http://jsfiddle.net/a9W5T/
You can use
:first-child, :nth-of-type(1), :first-of-type or :nth-child(1n)
And why your code donst work, is because you use:
#kasticketProducts:first-child .aProduct
this will take the first element #kasticketProducts, use this instead: #kasticketProducts .aProduct:nth-child(2) {
color: red;
} <-- This will take the first element .aProduct inside your ID element
Another solution would be to style .aProduct, and then override the style for any succeeding occurrences of .aProduct using the general sibling combinator:
#kasticketProducts .aProduct {
// effectively becomes the style for the first occurrence of .aProduct
}
#kasticketProducts .aProduct ~ .aProduct {
// overrides the style set above for all occurrences of .aProduct,
// apart from the first
}
The biggest advantage of this approach is that it doesn't rely on the structure of the markup.
General sibling selectors on MDN
Here's an example
Check the #id, it's case sensitive
Also, be careful with quotes, you are not closing them.
<div id="kasticketProducts">
<div class="aProductHeader">aaa</div>
<div class="aProduct">aaa</div>
<div class="aProductHeader">aaaa</div>
<div class="aProduct">aaa</div>
For the first .aProduct get selected:
#kasticketProducts .aProduct:nth-child(2) {
/* your styles */
}
Sorry for that, thought was for getting the first kasticketProduct. Apologizes.