こんにちはjunです。最近、editor.jsだったり色々バニラJSを触る機会がありました。特定のNodeを取得する時にdocument.querySelector()
を使用することでCSS・jqueryライクに要素を取得できます。今回はIDを持つ要素をgetByElementId()
を使わず、querySelector()
を用いてquerySelector("#~~~")
と取得した時に遭遇したエラーについてです。
タイトルの通りなのですが、querySelector()
で先頭が数字のIDを指定するとエラーが起きます。
document.querySelector("#16test");
// VM490:1 Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#16test' is not a valid selector.
簡単にコンソールでチェックできます。「not a valid selector」の通り、有効なセレクタじゃないよと怒っています。なぜこんなことが起きるのかを調べたところ、querySelector()
はCSSセレクタの仕様を使っており、CSSのIDセレクタは「#の後に数字をつけてはいけない」という仕様があるからです。
Stackoverflow https://stackoverflow.com/questions/37270787/uncaught-syntaxerror-failed-to-execute-queryselector-on-document
上記のStackoverflowの回答が役に立ちました。HTML5の仕様としてはIDの最初の文字に数字を入れることは問題ありません。しかしCSS3のIDセレクタの仕様ではなんと、#のあとに数字を使用してはいけないと確かに書かれています。詳細はW3Cのこちらのページにあります。
they cannot start with a digit, two hyphens, or a hyphen followed by a digit.
第一の解決策はgetElementById()
を使うことです。そう思うと、本来DOMにIDを持つ要素は必ず一つなのでgetElementById()
を使えばいいのに、なんでquerySelector()
を使っていたんだろうか?と思っていたら、ランダムに生成したIDをもつ要素配下のある子要素を取得する処理を実装する際、querySelector(`#{id} .item`)
みたいな感じで実装してた時でした。
この場合ランダムに生成されるIDに数字が含まれないようにするか、getElementById(id)?.querySelector(".item")
として一旦getElementById()
を使ってからquerySelector()
を使うといいかなと思います。