Escaping characters in CSS class selectors

You are getting confused between the class name as present in the DOM, and the escaped version required in CSS. The class name is just specified as is:

elt.classList.add('foo:bar')

It is when this is referenced in a CSS file (or other CSS selector context, such as querySelector) that it must be escaped:

.foo\:bar { color: red; }

The same applies to the case where you choose to use a numeric escape:

elt.classList.add('1234');

.\31 234 { color: red; }

However, no amount of escaping will permit you to have spaces in class names. Spaces are absolutely reserved for delimiting multiple class names on the DOM className attribute.


Short answer: DOM parses whatever selector you pass to it as string. If the (parsed by DOM) result contains spaces or non-breaking-spaces, they will count as class separators.


You shouldn't worry about jQuery, or any other ECMAScript misinterpreting the spaces meant for ending an escape block as a class delimiter.

Simply put, because they are not in charge of this matching. Document Object Model is. The same DOM that interprets the escaped CSS classes. So if an escaped class name works in your stylesheet, it will work as a selector if passed by any JavaScript library.

On one condition: that it gets passed to DOM in a form that it understands. A form that works in CSS.

Now, let's assume that, for semantics reasons, you'd like to use the class 100% on an element. You'll need to escape at least the first and last characters for your selector to work. The ones in the middle may or may not be escaped. Possible selectors, all translating at DOM level to the 100% class name, would be:

  • .\31 00\25
  • .\31 0\30\25
  • .\31\30 0\25
  • .\31\30\30\25
  • .\31 \30 \30 \25

As you already know, there are more escaping CSS methods. However, this applies to all.

When you pass a selector to jQuery or JavaScript it will treat it as a string and pass it to the DOM parser. However, these libraries have their own escaping mechanisms, allowing us to do fancy stuff. So, to allow any of the above selectors to make it to the DOM parser you need to escape the backslashes, so they are not misinterpreted by JavaScript as escape characters and removed from string.

Basically you need to double your backslashes. Any of the following will do:

  • .\\31 00\\25,
  • .\\31 0\\30\\25,
  • .\\31\\30 0\\25
  • .\\31\\30\\30\\25
  • .\\31 \\30 \\30 \\25

Here's a snippet. Test it out. Add elements with class 0% and you will see they don't get selected. Because the DOM parser will turn any of the above selectors into 100% and match them against the 100% class you have put to the element.

$('.\\31\\30\\30\\25>div').on('click', function(){
  var positions = ['first','second','third'];
  alert('You clicked the ' + positions[$(this).index()] + ' div.');
})
.\31 0\30\25 > div{
  padding: 20px;
}
.\31 00\25 > *:first-child {
  color: red;
}

.\31\30 0\25 > *:nth-child(2) {
  color: blue;
}
.\31\30\30\25 > *:last-child {
  color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    <div class="100%">
        <div>first</div>
        <div>second</div>
        <div>third</div>
    </div>

Getting back to your example (abc\\20 def) it will parse and behave exactly like abc def. Spaces, when present in the final result of the class name string, will be interpreted as class delimiters. This goes for both \x20 and \xa0 (space and non-breaking-space) and it is the expected behaviour.

As an interesting (trivial) note, if for some evil reason you wanted to make it hard for people to style up your app, you could always add a command type character to a class name. Here's an example:

$('.space').removeClass('\x73\x70\x61\x63\x65').addClass('\x1a\x73\x70\x61\x63\x65');
.space {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="space">
  inspect me, i should be red!
</div>

I think you can use class="abc&amp;#x0020;def" to solve that problem