Search code examples
javascriptcssnullcss-selectors

How might I build a negative attribute selector in CSS?


I am experimenting (might be foolhardy) with reproducing in CSS what Douglas Crockford refers to as a bottom value.

What's a bottom value?

In Javascript, bottom values are undefined and null.

I can take a custom-data attribute:

data-my-custom-attribute=""

and I can give it a value of null (using Unicode U+2400):

data-my-custom-attribute="␀"

In CSS, I can then reference any custom-data attribute which is null:

[data-my-custom-attribute="␀"] {

  [... CSS PROPERTIES HERE...]

}

Next up, I'd like to deploy an equivalent to this Javascript:

if (myCustomAttribute !== null) { ... }

But it seems I can't reference any custom-data which isn't null, because something like this:

[data-my-custom-attribute!="␀"] {

  [... CSS PROPERTIES HERE...]

}

doesn't work and isn't valid.


Having established that:

  • [data-my-custom-attribute!="␀"]

doesn't work, it occurs to me that:

  • [data-my-custom-attribute]:not([data-my-custom-attribute="␀"])

actually does work (and if nothing else comes up, I'll stick with that).

Working Example:

div {
  display: inline-block;
  width: 100px;
  height: 100px;
  margin-right: 12px;
}

.rectangle {
  display: block;
  width: 450px;
  height: 60px;
  margin-top: 12px;
  background-color: orange;
}

[data-my-custom-attribute="red"] {
  background-color: red;
}

[data-my-custom-attribute="yellow"] {
  background-color: yellow;
}

[data-my-custom-attribute="blue"] {
  background-color: blue;
}

[data-my-custom-attribute="␀"] {
  border-radius: 0;
  background-color: black;
}

[data-my-custom-attribute]:not([data-my-custom-attribute="␀"]) {
  border-radius: 50%;
}
<div data-my-custom-attribute="red"></div>
<div data-my-custom-attribute="yellow"></div>
<div data-my-custom-attribute="blue"></div>
<div data-my-custom-attribute="␀"></div>

<div class="rectangle"></div>

However,

[data-my-custom-attribute]:not([data-my-custom-attribute="␀"])

feels awkward and verbose. Is there really nothing better?


Solution

  • Unfortunately, there isn't a more concise way. Even jQuery's [att!=val] selector, which has remained exclusive to jQuery all these years, doesn't require that the attribute be present to match, so you'd still need to pair that with [att].

    I understand this is an experiment with the bottom value concept, but for the sake of completeness I'll add that the closest things to a null attribute value in HTML (and by extension CSS) are either the empty string (the default value of custom data attributes), or the lack of the attribute entirely. The idiomatic way to achieve your desired result is to choose either the empty string or omission of the attribute altogether, and use a corresponding [data-my-custom-attribute=""] or :not([data-my-custom-attribute]) selector respectively in CSS, and if (myCustomAttribute === "") or if (("myCustomAttribute" in myDiv.dataset) === false) respectively in JS.