Categories
css css-selectors

Which characters are valid in CSS class names/selectors?

1302

What characters/symbols are allowed within the CSS class selectors?
I know that the following characters are invalid, but what characters are valid?

~ ! @ $ % ^ & * ( ) + = , . / ' ; : " ? > < [ ] \ { } | ` #

6

1099

You can check directly at the CSS grammar.

Basically1, a name must begin with an underscore (_), a hyphen (-), or a letter(az), followed by any number of hyphens, underscores, letters, or numbers. There is a catch: if the first character is a hyphen, the second character must2 be a letter or underscore, and the name must be at least 2 characters long.

-?[_a-zA-Z]+[_a-zA-Z0-9-]*

In short, the previous rule translates to the following, extracted from the W3C spec.:

In CSS, identifiers (including element names, classes, and IDs in
selectors) can contain only the characters [a-z0-9] and ISO 10646
characters U+00A0 and higher, plus the hyphen (-) and the underscore
(_); they cannot start with a digit, or a hyphen followed by a digit.
Identifiers can also contain escaped characters and any ISO 10646
character as a numeric code (see next item). For instance, the
identifier “B&W?” may be written as “B&W?” or “B\26 W\3F”.

Identifiers beginning with a hyphen or underscore are typically reserved for browser-specific extensions, as in -moz-opacity.

1 It’s all made a bit more complicated by the inclusion of escaped unicode characters (that no one really uses).

2 Note that, according to the grammar I linked, a rule starting with TWO hyphens, e.g. --indent1, is invalid. However, I’m pretty sure I’ve seen this in practice.

3

  • 63

    NB: The W3C says that the use of a leading ‘-‘ or ‘_’ should be reserved for vendor-specific CSS extensions (e.g., -moz* classes implemented by Mozilla browsers).

    – mipadi

    Jan 15, 2009 at 23:44

  • i added sample of not starting with _ – or letter but emoji. I do NOT recommend such naming for classes yet it works. Good to know for general curiosity. stackoverflow.com/a/69963534/1737158

    Nov 14, 2021 at 13:41


  • 1

    As of 2022, the CSS spec defines a class-name (in a .css rule’s selector) as "." + ident, and the lexical scanner rules for ident specifially allow any character outside of 0x00-0x7F in a class name after an initial [_A-Za-z] character, so the [_a-zA-Z0-9-]* pattern posted here is incorrect.

    – Dai

    Mar 9 at 9:18


207

To my surprise most answers here are wrong. It turns out that:

Any character except NUL is allowed in CSS class names in CSS. (If CSS contains NUL (escaped or not), the result is undefined. [CSS-characters])

Mathias Bynens’ answer links to explanation and demos showing how to use these names. Written down in CSS code, a class name may need escaping, but that doesn’t change the class name. E.g. an unnecessarily over-escaped representation will look different from other representations of that name, but it still refers to the same class name.

Most other (programming) languages don’t have that concept of escaping variable names (“identifiers”), so all representations of a variable have to look the same. This is not the case in CSS.

Note that in HTML there is no way to include space characters (space, tab, line feed, form feed and carriage return) in a class name attribute, because they already separate classes from each other.

So, if you need to turn a random string into a CSS class name: take care of NUL and space, and escape (accordingly for CSS or HTML). Done.

0

    84

    I’ve answered your question in-depth here: http://mathiasbynens.be/notes/css-escapes

    The article also explains how to escape any character in CSS (and JavaScript), and I made a handy tool for this as well. From that page:

    If you were to give an element an ID value of [email protected]$%^&*()_+-=,./';:"?><[]{}|`#, the selector would look like this:

    CSS:

    <style>
      #\~\!\@\$\%\^\&\*\(\)\_\+-\=\,\.\/\'\;\:\"\?\>\<\[\]\\\{\}\|\`\#
      {
        background: hotpink;
      }
    </style>
    

    JavaScript:

    <script>
      // document.getElementById or similar
      document.getElementById('[email protected]$%^&*()_+-=,./\';:"?><[]\\{}|`#');
      // document.querySelector or similar
      $('#\\~\\!\\@\\$\\%\\^\\&\\*\\(\\)\\_\\+-\\=\\,\\.\\/\\\'\\;\\:\\"\\?\\>\\<\\[\\]\\\\\\{\\}\\|\\`\\#');
    </script>