5

I'm trying to select <a> elements that are not the parents of <img> elements. (Note: if it's relevant some of the anchors I want to select are childless.) I tried this:

a > :not(img) {}

and this:

a:not(> img) {}

but neither of them seem to work. How would I accomplish this in CSS?

James Ko
  • 32,215
  • 30
  • 128
  • 239

2 Answers2

7

There is a spec, currently in draft, for a :has() pseudo-class. No browser supports it yet. If the spec is someday approved and implemented, you'd be able to do this:

a:not(:has(img)) {
    // Styles
}

The MDN page says that :has would never work in stylesheets, only in JavaScript; but in saying that, it links to a section of the spec about a "dynamic selector profile" that apparently no longer exists.

I think the browser vendors typically have a problem with implementing CSS features that require knowledge of the DOM that only exists after the selected element is created, so I don't know if we should get our hopes up for this. Someone who follows the mailing lists or is generally smarter than me might offer a better prognosis.

75th Trombone
  • 1,364
  • 15
  • 28
  • The static and dynamic profiles were recently renamed to snapshot and live respectively, breaking links (which I'm gonna have to find and fix in all my answers here as well, just something you have to do when attempting to cite, or in the case of MDN document, an unstable spec and not something I'd be complaining about). The profiles themselves have not gone away. But there still haven't been any new developments or findings on how well :has() would perform in either profile since 2015. Your reasoning isn't that far off and is why the profiles exist in the first place. – BoltClock Apr 07 '18 at 02:52
  • Do you know why `:has()` wouldn't perform well? I know that CSS selectors are implemented from right to left (i.e. `a img` selects all `img` elements, then filters out the ones without `a` ancestors). It seems like it would be simple to implement a parent selector by simply getting the parent of each of the selected nodes, right? – James Ko Apr 07 '18 at 04:18
  • I read the Bugzilla thread on :has today. One example it gave is that if you allowed `:has(:hover)`, a naïve implementation would have to recompute the style of every element in the document on every mouseenter or mouseleave event. – 75th Trombone Apr 07 '18 at 04:38
  • @James Ko: Because :has() [isn't just a parent selector](https://stackoverflow.com/questions/27982922/latest-on-css-parent-selector/27983098#27983098), so it's not as simple as implementing it as one. There have been talks of providing subsets of :has() such as E:has(> F) which *would* indeed function exactly like a parent selector, but as I've mentioned in my previous comment no work has been done on this by browser vendors at all since 2015, so nobody knows *if* it would perform well or poorly, let alone why. The dynamic pseudo-class example 75th cited is another possible reason. – BoltClock Apr 08 '18 at 16:53
1

Unfortunately, no. You'd need to use jQuery.

You could do some kind of workaround using CSS:

  1. Assign a class to links that do not have child elements that are images and use that class to style the links as normal (e.g. a.class{color: red})

  2. Assign a class to links that do have an image child element, and use a:not(.class){} to change their color

Reason: There is no parent selector in CSS. See: Is there a CSS parent selector?, CSS Parent/Ancestor Selector

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Hee Jin
  • 145
  • 7