2

At the moment I'm writing a webchat, in which the user can open a new room with URI-GET params. The PHP part creates the html and sends it to the browser. But if the user types in the URI something like /?Mychat%20%231 my PHP sends a chat named Mychat_#1. This still works correctly but when I try to refresh the chat (every second) I always get

SyntaxError: 'section.Mychat_#1' is not a valid selector

Every chat looks like this:

<section class="chat-container chat_name_#1"><!-- <- I try to get this node via the chat name -->
    <header>
        chat_name_#1
    </header>
    <div class="msg-container" style="">
        <section><!-- here the messages will be inserted --></section>
    </div>
    <footer>
        <div class="msg">
            <input name="msg" autocomplete="off" type="text">
        </div>
        <div class="btn">
            <button>senden</button>
        </div>
    </footer>
</section>

in my main.js file I tried to get the node with document.querySelector

for(DATA in CHAT){
    let chat = document.querySelector('section.' + CHAT[DATA].title);
    // ...
}

Normal the hashtag character is allowed in class names (if they don't start with it)


My Question is not a duplicate of Which characters are valid in CSS class names/selectors.

Before I asked it, I searched on Google and find it too. I read it but there was only explained, what CSS selectors are allowed. In my case it unfortunately didn't help.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Christian
  • 151
  • 1
  • 11
  • @Karl-Johan Sjögren: But this isn't about the id attribute. – BoltClock Aug 30 '17 at 06:36
  • The same goes for the class field, you can't have a # in it. – Karl-Johan Sjögren Aug 30 '17 at 06:36
  • @Karl-JohanSjögren of course you can. Whether that string is a valid selector is another question – Phil Aug 30 '17 at 06:37
  • @Karl-Johan Sjögren: [I'm sorry?](https://checker.html5.org/?showsource=yes&doc=data%3Atext%2Fhtml%3Bcharset%3Dutf-8%2C%3C%21DOCTYPE+html%3E%3Ctitle%3E%2523+in+class+attribute%3C%2Ftitle%3E%250A%3Cdiv+class%3D%22Mychat_%25231%22%3E%3C%2Fdiv%3E) – BoltClock Aug 30 '17 at 06:38
  • 1
    Possible duplicate of [Which characters are valid in CSS class names/selectors?](https://stackoverflow.com/questions/448981/which-characters-are-valid-in-css-class-names-selectors) – Rajesh Aug 30 '17 at 06:39
  • 2
    Selectors use tokens so that the value can be parsed (see [*MDN*](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors)). If those tokens appear in values, they must be escaped or quoted. – RobG Aug 30 '17 at 06:42
  • @BoltClock Fine, it seems that html5 allows more values in both class and id attributes then I remember. But the problem is still that if he uses other then the recommended set his selector will not be valid. – Karl-Johan Sjögren Aug 30 '17 at 06:43
  • 1
    @Karl-Johan Sjögren: The restrictions in HTML and the restrictions in CSS were not designed with one another in mind. They are completely unrelated. – BoltClock Aug 30 '17 at 06:44
  • I would disagree, back in HTML4 and CSS2.1 they hade a lot of similarities which I doubt is a coincidence. There might not have been any collaboration between the working groups but they all knew their specifications needed to work together in the end. – Karl-Johan Sjögren Aug 30 '17 at 06:47

2 Answers2

3

The hash is allowed in class names, but it represents an ID selector. This is the case even when your class name contains a hash. So your selector is being treated as a class selector followed by what appears to be an ID selector. The direct cause of the SYNTAX_ERR here is that ID selectors consist of a hash followed by an ident, and an ident cannot start with a digit (see section 4 of the CSS2 spec).

To use the hash in a class selector you need to escape it with a backslash, but if you have control over the PHP that generates these class names you're better off just doing away with the hash altogether as it only serves to cause more trouble than it's worth. Note that the hash also represents a fragment identifier in the URL, which is why it's encoded as %23 in your URL (see also Why is "#.id" a bad selector in CSS/jQuery yet it works in an HTML anchor?). So that's two reasons not to use a hash in a class name just because it's allowed in HTML5.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • Ok, thanks. I'll replace it with anything else when it make so many problems ... maybe with a space – Christian Aug 30 '17 at 06:51
  • "*…and an ident cannot start with a digit*" that is soooo HTML 4! If "ident" means "id" then the version of HTML after 4.1 (sometimes called HTML5 but just [*HTML*](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) according to WHATWG) allows pretty much any character in IDs: "*There are no other restrictions on what form an ID can take; in particular, IDs can consist of just digits, start with a digit, start with an underscore, consist of just punctuation, etc.*" I don't think any browser ever enforced the "can't start with a number" rule anyway. ;-) – RobG Aug 30 '17 at 06:53
  • 1
    @RobG: "ident" means "identifier". It's a CSS tokenization term. Nothing to do with the HTML id attribute. Yep, exactly why the restrictions were removed - they were never enforced anyway. – BoltClock Aug 30 '17 at 06:56
  • Then the meaning of "ident" should be clarified. In the context of the answer I can only interpret it as "the ID value to match", e.g. given `id="foo"` then the ID value to match is "foo". Maybe I should find a CSS selector parsing resource… – RobG Aug 30 '17 at 07:01
  • 1
    @RobG: There really needs to be a good canonical question for this. Personally I'm getting tired of repeating the same things across so many of my answers to various questions that all boil down to the same thing ;) – BoltClock Aug 30 '17 at 07:08
  • @BoltClock—you could always write one. ;-) – RobG Aug 30 '17 at 12:38
1

It seems that class selectors cannot have unescaped # characters in them even though it is valid in the class attribute. This is because an unescaped # immediately signals an id selector.

One option is to use an attribute selector. For example...

document.querySelector([
  `section[class="${CHAT[DATA].title}"]`,   // exact match, only one class
  `section[class^="${CHAT[DATA].title} "]`, // starts-with
  `section[class$=" ${CHAT[DATA].title}"]`, // ends-with
  `section[class*=" ${CHAT[DATA].title} "]` // contains among other classes
].join(','))
Phil
  • 157,677
  • 23
  • 242
  • 245