Tuesday, November 1, 2016

CSS3: Match parameter contents with the :not pseudoclass

It's possible to match parameter contents in the :not (negation) pseudoclass used in Cascading Style Sheets Level 3 —

A:not([href*="subdomain.domain.tld"]) {color:blue;}

All links are colored blue except those targeting anything that contains subdomain.domain.tld .

The asterisk * before the equals sign = means, that the match is any parameter value inside double quotes (quotes may be optional or pursuant to syntax) — in this case, links (A) that contain subdomain.domain.tld — to which a particular CSS rule is not applied using :not([]). Here, link contents can be a variation of
https://subdomain.domain.tld/directory/folder/file.html

More complex use of the :not pseudoclass:

A[TARGET="_blank"]:not([href*="subdomain.domain.tld"]) SPAN {color:yellow}

All SPAN elements inside links (A) with TARGET="_blank" (these typically open new windows) are colored yellow; except those, where link address contents match subdomain.domain.tld

Approximation in HTML:
<A HREF="https://domain.tld" TARGET="_blank"><SPAN>Text in this link's SPAN element is colored yellow.</SPAN></A>

<A HREF="https://subdomain.domain.tld/folder/file.html" TARGET="_blank"><SPAN>
Text in this link's SPAN element is not colored yellow, because it matches subdomain.domain.tld .</SPAN></A>
The W3C CSS3 spec itself is rather fuzzy about all this, but after some experimenting, I got a satisfactory result with a userstyle.

And if it works in a modern version of Firefox, it should work in other browsers, too.

Additional notes

If you want to match by the existence of a parameter inside an element, such as ENABLED inside <BUTTON>, or use a simple selector, such as a .classSelector or #idSelector — then you have to do without square brackets []:
A:not(TITLE) {}
   /* all links that do not contain TITLE
      (without tooltips on link hover) */

BUTTON:not(DISABLED) {}
   /* all buttons that are enabled */

DIV:not(.frontpage) {}
   /* all DIV elements not with class="frontpage" */

DIV:not(#articleContents) {}
   /* all DIV elements not with id="articleContents" */
...and so on.

Other selector matching rules apply, too.

Errata

Strangely enough, I found it impossible to insert or nest a negation pseudoclass into a series of combining selectors (with Firefox 39.0.3):

DIV A:not([href*="subdomain.domain"]) SPAN {parameter:value;}

— where a multi-selector involving SPAN elements inside links without subdomain.domain and inside DIV elements would not work.

So, in a ruleset, the negation pseudoclass must be listed first, and can include child selectors, but cannot be a child selector itself.

Rationale

As it was, this post was borne out of a need in a userstyle (made to improve the functionality of one website) to give all links that open in new windows using TARGET="_blank" a certain visible background, which was a yellow gradient, so that the reader could decide how they should open those links.

The exception to that rule was to avoid setting that background to weather content, as it was based on elements for which the website applied its own background images. Incidentally, these backgrounds were dynamically applied to child elements inside links with TARGET="_blank", and setting one's custom background replaced the background images, and weather information was thus lost.

As the links resolved to the website's weather subsite, then excluding those required matching the weather-themed subdomain, as in weather.website.tld and the links' SPAN, B, and other child elements that already contained backgrounds.

Of course, I could have specifically targeted several large and content-heavy parent DIV elements that did not contain weather content, but this would certainly have required involving way more than one such DIV element.

I could have also tried using a negation pseudoclass with a simple selector, as in:

DIV:not(.thisclass) A[TARGET="_blank"] {background:gradient(to left, yellow 0px...)}

... and maybe this would have worked, too. — But then I would have risked missing several non-weather links that did open in new windows, and as such, these would in turn have remained potentially invisible.

Therefore I found it more prudent to use link-based selectors.

Article Errata:
Corrected terminology of :not being a pseudoclass instead of a pseudoelement.

No comments: