The anywhere combinator :has()

For the first time, I have styled a document by its meta tags. How? By using :has() as an anywhere combinator. It can detect any tag in the document, and style any other, if the first tag is present.

On a news site, where every article was tagged with topics like “economy”, “election”, “pride”, etc., I wanted to style articles with certain topics. Ideally, we would have the tags as classes or data attributes to be picked up in CSS. But on this particular site, the tags were not exposed, and we couldn’t alter the code to add them.

But there were <meta> tags like this, in <head>:

<meta property="article:tag" content="DuckTales">

The :has() selector can detect if the document contains this tag, and go on to select any other element:

Neat!
:has(meta[property="article:tag"][content="DuckTales"]) article {
  border-left: 3rem dotted #b0d;
}

What else could this be useful for? Act on the viewport meta tag? Apply styles only when a certain script is present? Show a warning whenever the page contains external links?

:has(meta[name="viewport"][content="width=device-width, initial-scale=1"]) article {
  border-right: 3rem dotted #b0d;
}

:has(script[src="https://example.com/analytics.js"]) article {
  border-top: 3rem dotted #b0d;
}

:has(a[href^="http"]) article::before {
    display: block;
    color: red;
    content: 'Careful! This page contains external links.';
}

Be aware that Firefox devtools flags this as “This selector uses unconstrained :has(), which can be slow”. It’s probably wise to make the selectors as narrow as possible.

head:has(meta[property="article:tag"][content="DuckTales"]) ~ body article {
  border-left: 3rem dotted #b0d;
}

:has() is pretty well supported by now. Firefox will support it in version 121, due December 19 2023.