Is there a shorthand for [:not] Pseudo class? - css

I was wondering if there is a shorthand for CSS pseudo selectors, since I have 4 repeated [:not] selectors.
div > h3 ~ div:nth-child(5):not(.no-need-2 > div):not(.no-need > div):not(p
~ div):not(.no-need)

The title asks a very general question which I am not sure how to interpret so this answer sticks to the specific situation with the :not pseudo class.
See MDN
The :not() pseudo-class requires a comma-separated list of one or more selectors as its argument. The list must not contain another negation selector or a pseudo-element.
For the selector given in the question therefore you could use
div > h3 ~ div:nth-child(5):not(.no-need-2 > div, .no-need > div, p ~ div, .no-need)
Most common browsers now support this list format but check https://caniuse.com/?search=not

Related

CSS rule is executed with and without :not() selector [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.

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.

What does the CSS `not` selector do?

I saw the following snippet in a css file. What does it do?
h3 ~ *:not(h3) {
margin-left: 15px;
}
Obviously it alters h3 headers in some way but I don't understand what ~ *:not(h3) does.
Googling ~ *:not(h3) is unproductive.
The isn't HTML. It is a CSS selector.
Specifically, it is 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.
Obviously it alters h3 headers
No, it does exactly the opposite. It stops the selector from matching h3 elements.
This is CSS, not HTML. See Mozilla's documentation on the CSS negation pseudo class for more details, but not basically selects elements that do not match the specified selector (in this case, h3).

nesting inside css :not() selectors

Is it possible to have nested values inside the :not selector? For eg:
:not(div > div)
Whenever I tried it, it does not seem to work.
Perhaps you need to use it another way which I have not figured out?
So far, in all the examples I see, you can only use one value inside this selector.
:not() only accepts one simple selector at a time; this is mentioned in the Selectors 3 spec:
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.
The simple selectors in your example would be the two div tokens that you have. Other simple selectors include class selectors, ID selectors, attribute selectors and pseudo-classes. It does not accept more than one simple selector, nor does it accept combinators like > or space.
Depending on which elements you're trying to select exactly, there may not be a way to exclude div > div:
If you only want to select elements that are children of a div, that are themselves not div, use this instead:
div > :not(div)
If you only want to select div elements whose parent element is not a div, use this instead:
:not(div) > div
If you want to use this negation by itself, selecting all other elements, then there isn't a way using just a selector.
The only other viable workaround in CSS that I can think of is to apply styles to the elements you want without the :not() expression, then undo them for div > div. This works for any set of elements you're trying to target; the disadvantage is that not all properties can be easily reset.
Alternatively, if you're using jQuery, which does support :not(div > div) unlike the CSS version, you can place the selector in a script and, for instance, have jQuery apply a class name to those elements then target that class in your CSS.
It should work now thanks to Selectors Level 4 which allows :not() to take a list of complex selectors.
You can now also nest :not()... like :not(:not()) which wasn't allowed in Selectors Level 3. Not sure why you'd want to do that but you can.

Is there a way to mix ids and classes with > in CSS

What I want to do is something like:
#div_id > .some_class
{
}
I don't want to change the class everywhere. I only want to change the class if it in that particular div.
Is ther some other way to do that same thing?
You've already stumbled upon the answer yourself:
#div_id > .class {
/* CSS magic */
}
This selects .class if it is the direct descendant of #div_id. For all descendants regardless of depth, use the selector #div_id .class instead.
See also this JSFiddle.
Your question already contains the child combinator CSS selector and will target the elements with class .some_class that are children of the element with id div_id, so if you have only one <div> with an id of div_id then it will only target the child elements with the class some_class. So it should work as already expected, except in IE6 of course which does not support that selector natively.
If you want to select grandchildren, use the descendant combinator.
Child combinator body > p
Descendant combinator body p
You essentially have the answer there. If you want to modify all classes with in a div then the selector would be div#id .this_class. If it's just one instance of the class inside the div (say you have a div called 'test' with three divs with a class of 'test_class' then you could either use the :nth-child() selector or the :first-of-type selector.
Your code looks fine to me. Note that the > operator will only affect the children of the DIV not any lower decendants (i.e. grandchildren). Remove the > to affect everything inside the DIV with the class .some_class.

Resources