1266

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

~ ! @ $ % ^ & * ( ) + = , . / ' ; : " ? > < [ ] \ { } | ` #
Arsen Khachaturyan
  • 6,472
  • 4
  • 32
  • 36
Darryl Hein
  • 134,677
  • 87
  • 206
  • 257
  • 5
    Related question: http://stackoverflow.com/questions/2812072/allowed-characters-for-css-identifiers – BalusC Jul 07 '10 at 17:17
  • 36
    what about utf8 characters? Like i may type in greek – GorillaApe Nov 27 '10 at 17:33
  • 10
    Special characters can be used in class names by escaping them - in your CSS file you can define a `.hello/world` class by escaping the backslash: `.hello\2fworld`, `hello\2f world` or `hello\/world` – wyqydsyq Jun 05 '12 at 00:18
  • 1
    Another related question, not about "syntax of names", but about "syntax of class attribute" when [expressing multiple names](http://stackoverflow.com/q/13808846/287948). – Peter Krauss Dec 11 '12 at 03:41
  • @DarrylHein: The incorrect assumption is that CSS class selectors may not contain `-` or `_`. – chharvey Mar 13 '15 at 00:07
  • 3
    You can also use emoji. https://www.npmjs.com/package/postcss-modules-emoji-classname – Kevin Suttle Oct 04 '16 at 05:10
  • 1
    You can even use emojis – Ric Jul 22 '18 at 06:07

10 Answers10

1070

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.

Vlad Didenko
  • 3,613
  • 4
  • 22
  • 34
Triptych
  • 188,472
  • 32
  • 145
  • 168
  • 62
    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 '09 at 23:44
  • 3
    The \-escapes are commonly used, but generally mostly for the purposes of CSS hacks, isolating browsers that don't support them. – bobince Jan 15 '09 at 23:59
  • @Paolo - if you stick to the guideline of only using underscores for browser-specific extensions, then there is no harm in IE6 ignoring them – Triptych Jan 16 '09 at 00:02
  • You can use escape notation to represent different characters. This can be useful, say, for targeting the underscore as the first character and having IE6 recognize it, as such: \\_ – arxpoetica Oct 19 '10 at 19:16
  • 5
    To update @Pim Jager's comment over two years later, according to http://www.w3counter.com/globalstats.php IE6 is now used by less than 3% of users, behind IE9 on 4%, IE7 on 9%, IE8 on 22%. All versions of Firefox have 28%, all versions of Chrome have 17%. – Daniel Earwicker Jun 15 '11 at 13:49
  • 3
    I know this is an old answer, but CSS (at least 2+) allows any *{Non-ASCII}* character in identifiers. – user2864740 Feb 12 '14 at 18:57
  • Regarding the comment by @mipadi: I don't think this a problem in practice (correct me if I'm wrong). Even if I name a class something as unconventional as "-moz-any" (which is not something I plan to do) it still won't clash with ":-moz-any" unless I also happen to write an invalid selector. – Albin May 13 '15 at 22:15
  • A rule starting with two hyphens is a CSS variable, which has special meaning and is supported by Firefox. – Sheepy Jun 02 '15 at 06:33
  • [CSS identifiers can now start with two hyphens](http://stackoverflow.com/q/30819462/1529630). – Oriol Jul 01 '15 at 22:53
  • 12
    `In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_); they cannot start with a digit, two hyphens, 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"`. So - `--indent1` is invalid and needs to be escaped as `\--indent1` (`--` classes break on iOS, for example) – eithed Oct 12 '15 at 13:51
  • On a related note: your grammar allows a single character string? What do you think is the best way to fix that? – bigOmega Mar 03 '16 at 19:54
  • @ bigΩmega I believe single character names are valid as long as they start with a letter or underscore. – Triptych Mar 03 '16 at 21:25
  • @Triptych why the plus after the first character set (`[_a-zA-Z]+`)? If I'm reading the spec right, it can only occur once: either as the first character of the name or the character following the opening hyphen. – typo Sep 24 '19 at 02:44
194

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.

Robert Siemer
  • 26,279
  • 9
  • 72
  • 84
  • 8
    The first line of your answer should be "most answers here are outdated/apply only to CSS2". – Salman A Nov 22 '14 at 16:18
  • 10
    @SalmanA The answers I refer to were wrong from the beginning. They neither apply to CSS2.1, CSS2 nor CSS1. – Robert Siemer Nov 22 '14 at 23:37
  • @RobertSiemer good point, I moved my comment to https://stackoverflow.com/questions/50812118/is-it-possible-to-use-the-spacecharacter-in-css-class-names-in-html (which is never the less related to this topic) – Peter T. Jun 12 '18 at 08:03
  • And JavaScript implementation: https://github.com/mathiasbynens/CSS.escape/blob/master/css.escape.js – Duarte Cunha Leão Nov 07 '19 at 16:22
  • 1
    For anyone curious: Common Lisp is an example of a programming language that allows escaping characters in identifiers. – texdr.aft Feb 09 '21 at 15:53
78

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 ~!@$%^&*()_+-=,./';:"?><[]{}|`#, the selector would look like this:

CSS:

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

JavaScript:

<script>
  // document.getElementById or similar
  document.getElementById('~!@$%^&*()_+-=,./\';:"?><[]\\{}|`#');
  // document.querySelector or similar
  $('#\\~\\!\\@\\$\\%\\^\\&\\*\\(\\)\\_\\+-\\=\\,\\.\\/\\\'\\;\\:\\"\\?\\>\\<\\[\\]\\\\\\{\\}\\|\\`\\#');
</script>
Eric
  • 6,347
  • 5
  • 37
  • 61
Mathias Bynens
  • 130,201
  • 49
  • 208
  • 240
  • 4
    @Darryl Of course, this is a pretty extreme example, but stuff like [`class="404-error"`](http://mothereffingcssescapes.com/#404-error) can be useful. – Mathias Bynens Jul 07 '11 at 15:12
  • i have an example: i convert a syntax highlighting system’s output to CSS. it has class names like “ISO C++:Types (*_t/*_type)”. if i only replace whitespace i have valid class names. – flying sheep Jul 11 '14 at 13:44
  • On your website, you say that the space character can be backslash escaped. When I try it in a class name, I can't get it to work. I notice there is no space in this example. Is it possible? – Adamarla Dec 14 '16 at 16:31
  • @Adamarla `

    ` adds two classes to the `p` element: `foo`, and `bar`. There is no way (that I can think of) to add a classname containing whitespace to an HTML element. The information on how to escape whitespace characters was included because it’s useful to escape such characters in other identifier contexts, e.g. font family names.

    – Mathias Bynens Dec 22 '16 at 08:22
  • 3
    As with most things in life it seems in CSS that there is a difference between "technically legal to the extreme" and "sane". – Volksman Jan 27 '17 at 21:14
  • @MathiasBynens I really would appreciate if you could have a look at my question https://stackoverflow.com/questions/50812118/is-it-possible-to-use-the-space-character-in-css-class-names which is related to this one, as you really seem to have an in depth understanding of the specification. – Peter T. Jun 13 '18 at 07:54
70

Read the W3C spec. (this is CSS 2.1, find the appropriate version for your assumption of browsers)

edit: relevant paragraph follows:

In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-z0-9] and ISO 10646 characters U+00A1 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".

edit 2: as @mipadi points out in Triptych's answer, there's this caveat, also in the same webpage:

In CSS, identifiers may begin with '-' (dash) or '_' (underscore). Keywords and property names beginning with '-' or '_' are reserved for vendor-specific extensions. Such vendor-specific extensions should have one of the following formats:

'-' + vendor identifier + '-' + meaningful name 
'_' + vendor identifier + '-' + meaningful name

Example(s):

For example, if XYZ organization added a property to describe the color of the border on the East side of the display, they might call it -xyz-border-east-color.

Other known examples:

 -moz-box-sizing
 -moz-border-radius
 -wap-accesskey

An initial dash or underscore is guaranteed never to be used in a property or keyword by any current or future level of CSS. Thus typical CSS implementations may not recognize such properties and may ignore them according to the rules for handling parsing errors. However, because the initial dash or underscore is part of the grammar, CSS 2.1 implementers should always be able to use a CSS-conforming parser, whether or not they support any vendor-specific extensions.

Authors should avoid vendor-specific extensions

Jason S
  • 171,795
  • 155
  • 551
  • 900
  • I was referring to your second edit about leading dashes and underscores, but forgot to clarify that. Sorry for the confusion. – Albin May 14 '15 at 01:25
25

The complete regular expression is:

-?(?:[_a-z]|[\200-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])(?:[_a-z0-9-]|[\200-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])*

So all of your listed character except “-” and “_” are not allowed if used directly. But you can encode them using a backslash foo\~bar or using the unicode notation foo\7E bar.

Gumbo
  • 594,236
  • 102
  • 740
  • 814
  • why `[\200-\377]`? `[\178-\1114112]` is allowed unescaped in CSS 3. – flying sheep Jul 11 '14 at 13:46
  • `\377` here is actually wrong. There's a note on the Grammar of CSS2.1's Lexical Scanner section which states: "The "\377" represents the highest character number that current versions of Flex can deal with (decimal 255). It should be read as "\4177777" (decimal 1114111), which is the highest possible code point in Unicode/ISO-10646." It also should be from `\240` as well, not `\377`. I guess this is 7 years old now though so things have probably changed a bit since then. – James Donnelly Mar 18 '16 at 14:50
  • 1
    I believe a more accurate regular expression would be `-?(?:[_a-z]|(?![\u0000-\u0239]).*|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])(?:[_a-z0-9-]|(?![\u0000-\u0239]).*|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])*`. – James Donnelly Mar 18 '16 at 16:06
  • 2
    @JamesDonnelly Please feel free to edit my answer if you think it needs some update. – Gumbo Mar 18 '16 at 18:12
12

For those looking for a workaround, you can use an attribute selector, for instance, if your class begins with a number. Change:

.000000-8{background:url(../../images/common/000000-0.8.png);} /* DOESN'T WORK!! */

to this:

[class="000000-8"]{background:url(../../images/common/000000-0.8.png);} /* WORKS :) */

Also, if there are multiple classes, you will need to specify them in selector I think.

Sources:

  1. https://benfrain.com/when-and-where-you-can-use-numbers-in-id-and-class-names/
  2. Is there a workaround to make CSS classes with names that start with numbers valid?
Community
  • 1
  • 1
D.Tate
  • 2,066
  • 3
  • 20
  • 31
5

My understanding is that the underscore is technically valid. Check out:

https://developer.mozilla.org/en/underscores_in_class_and_id_names

"...errata to the specification published in early 2001 made underscores legal for the first time."

The article linked above says never use them, then gives a list of browsers that don't support them, all of which are, in terms of numbers of users at least, long-redundant.

mofaha
  • 51
  • 1
  • 1
3

For HTML5/CSS3 classes and IDs can start with numbers.

Marius
  • 54,363
  • 28
  • 121
  • 143
  • 1
    Do you have a source for this? Maybe I'm missing something, but the [CSS3 selectors spec](http://www.w3.org/TR/css3-selectors/#id-selectors) links to the [identifiers definition](http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier) in the CSS 2.1 spec which doesn't permit leading numbers. – Ryan Nov 27 '10 at 21:45
  • 11
    http://www.w3.org/TR/2003/WD-css3-syntax-20030813/#characters – Jamie Pate Apr 15 '13 at 22:04
  • 10
    HTML 5 allows classes and IDs to begin with a number (e.g. `class="1a"`). However, a CSS identifier can't begin with a number (e.g. `.1a` won't work). You can escape it, tough (e.g. `.\31 a` or `.\000031a`). – Oriol Feb 16 '15 at 19:43
  • Although it normally works in CSS too, but looks like it's still not official. "Property names and at-rule names are always identifiers, which have to start with a letter or a hyphen followed by a letter, and then can contain letters, numbers, hyphens, or underscores." - http://www.w3.org/TR/css3-syntax/#syntax-description – Stickers Feb 27 '15 at 21:15
  • @Pangloss But class names aren't property names or at-rule names. – Bennett McElwee Jul 14 '15 at 23:30
  • Not sure what you mean by that @BennettMcElwee but see [this demo](http://jsfiddle.net/uczo3pfd/). – Stickers Jul 15 '15 at 01:37
  • I think OP also asked for names too @BennettMcElwee *"What characters are valid in CSS class names/selectors?"*, also we're commenting under this very particular answer. I agree with you on the points of attribute selectors, and your demo works. – Stickers Jul 15 '15 at 13:06
  • Leading numbers don't work. https://jsfiddle.net/tst1rbv1/ tried in IE11, FF39,Chrome44 – jawo Aug 18 '15 at 07:00
3

We can use all characters as class name. Even like # and . Just we have to escape it with \.

.test\.123 {
  color: red;
}

.test\#123 {
  color: blue;
}

.test\@123 {
  color: green;
}

.test\<123 {
  color: brown;
}

.test\`123 {
  color: purple;
}

.test\~123 {
  color: tomato;
}
<div class="test.123">test.123</div>
<div class="test#123">test#123</div>
<div class="test@123">test@123</div>
<div class="test<123">test<123</div>
<div class="test`123">test`123</div>
<div class="test~123">test~123</div>
doğukan
  • 14,001
  • 6
  • 27
  • 47
1

Going off of @Triptych's answer, you can use the following 2 regex matches to make a string valid:

[^a-z0-9A-Z_-]

This is a reverse match that selects anything that isn't a letter, number, dash or underscore for easy removal.

^-*[0-9]+

This matches 0 or 1 dashes followed by 1 or more numbers at the beginning of a string, also for easy removal.

How I use it in PHP:

//Make alphanumeric with dashes and underscores (removes all other characters)
$class = preg_replace("/[^a-z0-9A-Z_-]/", "", $class);
//Classes only begin with an underscore or letter
$class = preg_replace("/^-*[0-9]+/", "", $class);
//Make sure the string is 2 or more characters long
return 2 <= strlen($class) ? $class : '';
Manny Fleurmond
  • 336
  • 6
  • 17