skip to Main Content

I have 4 elements with a class of either x-control-ui or y-control-ui:

<div class="x-control-ui">x-control: <output id="x-control-output"></output></div> 
<input type="range" min="-4" max="4" step="0.1" value="0" class="param x-control-ui" id="x-control">

<div class="y-control-ui">y-control: <output id="y-control-output"></output></div> 
<input type="range" min="-4" max="4" step="0.1" value="0" class="param y-control-ui" id="y-control">

Using the [attribute*="value"] selector works as expected, selecting them all:

document.querySelectorAll("[class*='-control-ui']")
NodeList(4) [div.x-control-ui.hidden, input#x-control.param.x-control-ui.hidden, div.y-control-ui.hidden, input#y-control.param.y-control-ui.hidden]

but if I change *= to $=, using the [attribute$="value"] selector, then no elements are selected:

document.querySelectorAll("[class$='-control-ui']")
NodeList []

even though though both classnames end in control-ui.

The same behaviour is observed in up-to-date Chrome and Firefox. I have checked the docs in MDN and consulted other sources, and all seem to indicate that the $= operator should select elements whose specified attribute (in this case, class) ends with the given text.

I have tried modifying the selector in various ways, to no avail.
What am I missing?

2

Answers


  1. The thing about the class attribute in particular is that it’s kind of an old hack. The classes for an element appear separated by spaces in the class attribute value; it’s just a string. (Now, in 2024, there’s the classList API, but 20 years ago that did not exist.)

    The meaning of the class attribute is such that the ordering of the classes does not matter (well, it might in some bizarre edge cases, but that’s another topic). So a class string of "something foo-control-ui" is functionally the same as "foo-control-ui something". Because code often modifies the class of an element by adding and removing class names, the value of that attribute string at any time could mean the same thing but look different.

    Thus, your *= selector works because it looks for that fragment everywhere in the string. However, the $= selector only looks at the end of the class value. Sometimes, it might work, but it’s a very fragile way to write code.

    As you said in a comment, adding another class to be the "general" quality, and then a more specific class for the precise behavior (or whatever the class is supposed to do), is the more robust way to go. Within realistic bounds, it’s basically no cost to add as many classes as you like: some for CSS rules, some for behaviors, etc.

    Login or Signup to reply.
  2. You are facing problem with the selector [class$='-control-ui'], it’s just because this selector seek for those elements whose class attribute ends with '-control-ui' . but in your html elements the class names ends with other characters like div.x-control-ui.hidden. So because of this $= selector not able to find these elements. modify your html.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search