HTML id 속성과 CSS “identifier”의 스펙이 다른 이유 - feat. W3C Selector API 문서

created:
last-updated:

Uncaught SyntaxError - Failed to execute 'querySelector' 글에서 이어지는 DOM API, CSS Selector, 그리고 HTML Attribute의 역사적 층위 차이 에 대해 공부해본 내용 기록.

디버깅을 하면서 위 글을 쓸 때 “document.querySelector()는 HTML의 id 속성을 대상으로 하지만, CSS Selector 문법을 따르기 때문에 두 스펙이 완전히 일치하지 않는다” 는 이유에 대해 의문이 계속 남아있었다. 그래서 좀 더 찾아본 내용을 추가로 기록해본다.


HTML의 id 속성과 CSS의 “identifier”는 이름이 비슷하지만 태생과 역할이 다르다. 둘을 구분해보면, HTML의 id는 “문서 구조적 식별자”이고, CSS의 identifier는 “스타일링 언어의 문법 토큰”이라 서로 다른 문맥의 개념이다.

HTML은 브라우저가 DOM 트리를 만들 때 유효성을 보장하기만 하면 되지만, CSS는 문법적 파싱이 필요한 언어 이기 때문에 더 엄격한 규칙을 가지게 되었다.

CSS는 “스타일시트 언어”이기 때문에 문법 파싱 단계가 존재하고, 토큰 단위로 분석한다. 예를 들어, 이런 스타일링 코드가 있다고 했을 때, CSS 파서는 #1foo를 “숫자로 시작하는 identifier”로 인식하지 못해 문법 에러로 처리한다. 반면 HTML은 단순히 "1foo"라는 문자열을 id 속성값으로 저장할 뿐이므로 문제가 되지 않는다.

#1foo { color: red }
document.querySelector('#1foo') // ❌ CSS identifier로서 invalid (숫자로 시작)
document.getElementById('1foo') // ✅ HTML id로서 valid

즉,

웹 표준화 그룹 World Wide Web Consortium(W3C)의 웹앱스 워킹그룹(“Web Applications Working Group”)의 Selector API 스펙문서(https://www.w3.org/TR/selectors-api/) 를 더 찾아보면서 신기한 것을 알게 됐는데, 요약해보면 이렇다.

querySelector()CSS 파서를 재사용하는 문법적 구현체다.

document.querySelector()는 “DOM 검색 API”처럼 보이지만, 내부적으로 CSS Selector 엔진을 그대로 사용한다. 셀렉터에 넘긴 문자열은 브라우저의 CSS 파서에 전달되어, CSS 선택자 문법으로 해석된 다음 일치하는 요소를 찾는 방식이다.

HTML 팀과 DOM 팀은 “선택자 해석용 파서를 새로 만들지 않고 CSS 파서를 재활용”하는 기술적 문법 재활용을 한 것인데, 그 배경을 알아보면 이렇다.

Selectors, which are widely used in CSS, are patterns that match against elements in a tree structure [SELECT|SELECT][CSS21|CSS21]. The Selectors API specification defines methods for retrieving Element nodes from the DOM by matching against a group of selectors. It is often desirable to perform DOM operations on a specific set of elements in a document. These methods simplify the process of acquiring specific elements, especially compared with the more verbose techniques defined and used in the past.

CSS가 이미 갖고 있는 선택자 문법(태그, 클래스, id, 속성, 구조 등)을 DOM 탐색용 API로 재활용하자는 것이 핵심이다.

정리해보면, HTML과 CSS는 별개의 사양 영역이었다가 나중에 서로 연동된 셈이고, 선택자(API)가 CSS의 문법 체계를 따르도록 설계되었기 때문에 이러한 차이가 나타난 것이다. 알고나니 꽤나 합리적인 활용 방안이라는 생각이 든다.


그럼 위에서 짧게 정리한 HTML과 CSS 사양의 차이를 좀 더 자세히 정리해보자.