CSS Equivalent of :Has()

CSS alternative to li:has(+ .class) relational pseudo class and li:not(.class ~ li)

Is there any combination of pseudo classes and selectors that could do the trick in pure CSS?

There isn't; the reason :not(.centered ~ li) doesn't work is indeed that it only currently supports simple selectors — like :has(), :not() will only accept combinators in Selectors 4. Since there are no pseudo-classes that currently accept combinators, and the only available sibling combinators go forward, you are left with a very restricted domain language in this regard. This is why those additions to Selectors were made.

As for progress... progress on the :has() pseudo-class has been eh. Last I heard, the working group was still deciding between allowing a subset of :has() in CSS or separating that out into its own pseudo-class, and vendors were going to see how much of it they could implement in CSS for this to work. But I don't think there has been any data yet.

:has vs :matches - Selectors Level 4

In a nutshell:

  • E:has(rs1, rs2) matches E when a different element F matches any of the selector arguments in relation to E. If you know jQuery's :has() selector, this is exactly the same thing.

  • E:matches(s1, s2) matches E when E itself matches any of the selector arguments. Think of :matches() as the direct opposite of :not(), which matches E if E itself does not match any of the arguments.1 You can also think of :matches() as a pseudo-class version of jQuery's .filter() method.

    This notation is equivalent to concatenating every selector argument with E (provided you can actually concatenate them) such that you have a selector list (E)(s1), (E)(s2). For example, div:matches(.foo, .bar) is equivalent to div.foo, div.bar.

This fundamental difference is demonstrated most straightforwardly with the selectors div:matches(p) and div:has(p):

  • div:has(p) matches any div element that has a p descendant.
    This is very similar to div p, except the former targets the div
    and the latter targets the p.

  • Since a div can never be a p, div:matches(p) will never match
    anything. (Likewise, div:not(p) will match all div elements.)


Here's a more complex example with slightly less absurd selectors:

div:has(.foo, .bar)
div:matches(.foo, .bar)

With the following markup:

<div class="foo"></div> <!-- [1] -->
<div class="bar"></div> <!-- [1] -->

<div class="foo bar"> <!-- [2] -->
<p></p>
</div>

<div> <!-- [3] -->
<p class="foo"></p>
</div>

<div> <!-- [3] -->
<div> <!-- [3] -->
<p class="bar"></p>
</div>
</div>

<div> <!-- [4] -->
<div class="foo"> <!-- [5] -->
<p class="bar"></p>
</div>
</div>

Which elements are matched by which selectors?

  1. Matched by div:matches(.foo, .bar)
    The first div element has the "foo" class, and the second div element has the "bar" class, so each of these satisfies its respective selector argument in the :matches() pseudo-class.

  2. Matched by div:matches(.foo, .bar)
    The third div element has both classes, so it matches both selector arguments.

    A note on specificity: both of these arguments have equal specificity, making the total specificity (0, 1, 1), but when an element matches multiple selector arguments with different specificity values, the spec says that the specificity is that of the most specific argument that is matched.

  3. Matched by div:has(.foo, .bar)
    Each of these div elements has a descendant element (in this case, a p) with a class that matches its respective selector argument in the :has() pseudo-class.

  4. Matched by div:has(.foo, .bar)
    This div element has a div.foo descendant and a p.bar descendant, therefore it satisfies both relative selector arguments.

    A note on specificity: because :has() is not yet in the fast profile and is therefore tentatively excluded from CSS, the concept of specificity does not apply at all. There are plans to include a limited version of this in the fast profile for use in CSS, but there is nothing concrete as yet. Any new developments will be added at an appropriate time.

  5. Matched by div:matches(.foo, .bar) and div:has(.foo, .bar)
    This div element matches both pseudo-classes:

    • it is .foo (as it has the "foo" class), and
    • it has a descendant with the "bar" class.

    This element would also match div:matches(.foo, .bar):has(.foo, .bar), which would be a valid level 4 selector since a compound selector can have any combination of pseudo-classes.

Another difference between :matches() and :has() is that :has() accepts what's known as a relative selector. A relative selector has a scope; selector scoping is an entire topic in its own right, but for the purposes of :has(), the scoping element is always the element you attach the :has() pseudo-class to. But, more importantly, a relative selector can either have an implicit descendant combinator, or begin explicitly with a combinator such as >, + or ~ — this combinator is what links the rest of the relative selector to its scoping element.

For example, while :has() defaults to an ancestor-descendant relationship, you can pass a relative selector that begins with + and it then becomes an adjacent-sibling relationship: ul:has(+ p) matches any ul element that is directly followed by a p (and not necessarily one that contains a p descendant).

As for :matches(), while the overview table says that it accepts a list of compound selectors, AFAIK it hasn't yet been set in stone whether it will take a list of compound selectors or complex selectors, and in which profile (fast or complete). But a compound selector is simply the new name for what Selectors 3 currently calls a sequence of simple selectors and a complex selector is an entire series of compound selectors and combinators. A relative selector is more like a complex selector in that respect. See this answer for a non-exhaustive list of the various terms used in selectors.


1 Yes, that's "arguments" in plural — in Selectors 4, :not() can now accept a list of selectors as opposed to a single simple selector. A much-needed enhancement, but it's also to make it consistent with the other new functional pseudo-classes.

how to use :has in sass

What you want cannot be done using CSS since CSS has no parent selector and currently also no :has selector.

SASS cannot help you either since all SASS can do for you is make authoring CSS easier - in the end any pre-processor will compile your code to CSS which is the only thing the browser understands.
The only cross-browser solution here (still) is Javascript.

Edit Summer 2022: As of now, Safari supports :has(), and Chrome has support behind an experimental web platform features flag. Firefox is working on it.

Your style is going to look like this:

body:has(.app.rtl) .blah {
some: blah;
}

Does CSS have anything like jQuery's :has()?

No, there isn't. The way CSS is designed, does not permit selectors that match ancestors or preceding siblings; only descendants ( and >), succeeding siblings (~ and +) or specific children (:*-child). The only ancestor selector is the :root pseudo-class which selects the root element of a document (in HTML pages, naturally it would be html).

If you need to apply styles to the element you're querying with :has(), you need to add a CSS class to it then style by that class, as suggested by Stargazer712.

Faking the :has() parent selector using only CSS

In Gecko and WebKit, certain selectors can “jump” using <label for> and an associated <input> element positioned anywhere. This works unreliably, but is still kind of fun.

#before {

left: -9999px;

position: absolute;

}

#parent {

padding: 0.5em;

}

#before:hover + #parent {

background-color: #123;

color: white;

}

#label {

border: 0.1em solid #678;

border-radius: 0.2em;

display: inline-block;

padding: 0.5em;

}
<input type="checkbox" id="before">

<div id="parent">

<label for="before" id="label">Hover over me!</label>

</div>

What is the equivalent in CSS of the SASS/SCSS expression &$ ?

There is no equivalent for the expression &$selected in css. &$ Is not a special symbol in both of the languages.
&$selected in scss combine from 2 parts:

  1. &: sccc- right after the parent selector insert new sub-selectors. eample:

scss:

main-selector {
color: blue;

&.sub-selector {
display: block;
}
}

equivalent css:

main-selector {
color: blue;
}
main-selector.sub-selector {
display: block;
}

As you can see, the & symbol doesn't exist at all in css, and only apears in scss code.


  1. $selected - this means a variable in scss. In the css code you will not be able to know if there was using in variables in the source scss file.
    this variable can represent every thing in css- including selectors' names, specific colors, arrays of values, indexes, counter etc.
    I can't tell you what does this variable represent in your code according to the code that you published, even that I know that it is in use, the only thing that I know about it's value in your case, is that it include a selector (And I don't know which one).

It is important you to understand, that most of the new symbols in scss, created to save lines of css code (and I think you do). But to know exactly the final compilation to css from scss code, you need to publish the whole scss code, including the files import from the scss file itself.

I hope I made it more clearly now.

CSS Equivalent of the if statement

No. But can you give an example what you have in mind? What condition do you want to check?

Maybe Sass or Compass are interesting for you.

Quote from Sass:

Sass makes CSS fun again. Sass is CSS, plus nested rules, variables, mixins, and more, all in a concise, readable syntax.

JavaScript equivalent to CSS * (everything) selector

If you're using plain JavaScript, you can use the querySelectorAll() method:

document.querySelectorAll("*");

This will return a NodeList containing all the elements selected. To style them as the CSS does:

var nodes = document.querySelectorAll("*");
for(var i=0; i < nodes.length; i++) {
nodes[i].style.backgroundColor = "#000";
}

You can of course use any other styles. To be technically correct, you would have to wrap querySelectorAll() in Array.prototype.slice.call() to convert it to a fully-formed array instead of a NodeList, but for this purpose this is unnecessary.

However, the querySelectorAll() method is relatively new, so to ensure total support you might want to use this:

var nodes = document.getElementsByTagName("*");  // gets all elements
for(var i=0; i < nodes.length; i++) {
nodes[i].style.backgroundColor = "#000";
}

That does exactly the same thing but with a different method. querySelectorAll() should technically be used as this is its purpose but either works.

N.B.: If you're using jQuery it's even easier:

$("*").css("background","#000000");

Lastly, if it's just CSS control you want when selecting everything, you can use a CSS setup as described here by David Walsh. There is an example implementation of this in this script.



Related Topics



Leave a reply



Submit