HTML&CSS

[CSS] querySelector의 특수문자 이스케이프와 CSS.escape() 메서드 - CSS querySelector Special Character Escape

apost 2023. 1. 22. 17:06
HTML 요소를 선택하는 방법중 가장 기초적인 방법은 getElementById() 와 getElementByClassName() 입니다.
근본 메서드이므로 빠르고 직관적이지만, 복잡한 CSS 선택자를 사용할 수 없는 제약이 다소 있습니다. 그래서 우리는 querySelector(), 또는 querySelectorAll() 을 조금 더 많이 사용합니다.
속도를 제외하면 여러가지 면에서 더 뛰어나기 때문에 습관적으로 사용하는 querySelector() 메서드지만 예기치 못한 단점도 있습니다.
 
먼저 근본 HTML 요소(들) 선택자로 다음 요소를 선택해보겠습니다.
 
<div id="a[a]" class="b[b]"></div>
 
ID와 클래스 모두로 요소를 선택할 수 있고, 정확하게 선택이 됩니다.
getElementByClassName() 메서드는 반환되는 값이 컬랙션(복수의 선택된 요소를 선택할 수 있음)이기 때문에 1개의 요소가 선택되었지만 컬랙션(Collection)이 반환되었습니다.
 
console.log(document.getElementById('a[a]'));
console.log(document.getElementsByClassName('b[b]'));
 

 

같은 요소를 querySelector()로 선택해 보겠습니다.

정확하게 null 이 반환됩니다. 그러니까 요소를 선택할 수 없는 것입니다.

 
console.log(document.querySelector('#a[a]'));
console.log(document.querySelector('.a[a]'));
 
 

간단하게 이유를 설명하면, querySelector(), querySelectorAll() 메서드는 특수문자를 이스케이프 하지 않으면 정상적으로 CSS 쿼리 선택을 하지 못합니다.

앞서 요소의 ID와 클래스에는 대괄호([])가 포함되어 있고, 이 대괄호는 요소의 속성을 접근하는 특수 용도로 사용하는 문자입니다. 이 특수 문자를 일반 문자열로 변환 처리를 해야 "a[a]", 또는 "b[b]" 문자열로 된 ID, 또는 클래스명을 올바르게 인식할 수 있습니다.

 

전혀 다른 접근 방법이지만 다음처럼 <div> 요소의 ID가 "a"이고, 속성 이름 "a"가 정의되어 있다면 querySelector('#a[a]')는 해당 요소를 선택하게 됩니다. 중요합니다.

 

<div id="a" a="" class="b[b]"></div>
 
쿼리 선택자에 사용하는 특별한 문자인 "#", "[", "]", "(", ")", "{", "}", "." 문자들을 ID나 클래스이름에 사용한 경우, 모두 예외처리를 해야 합니다.
사실 이런 특수 용도의 문자들을 ID나 클래스명에는 사용하지 않는 것이 좋습니다.
자바스크립트의 유연성으로 인해 ID나 클래스명에 거의 무제한의 네이밍이 가능하다보니 생기는 일종의 부작용?입니다. 
권장하지는 않지만, 자바스크립트에서 허용을 하고 있으니, 이 특수 용도인 문자들은 이스케이프를 해야 합니다.
앞서 처음의 요소를 대괄호를 이스케이프 해서 쿼리 선택자로 선택을 해보겠습니다. 자바스크립트의 이스케이프 문자는 백슬래시입니다.

 

console.log(document.querySelector('#a\[a\]'));

 

널(null)이 나옵니다. 이스케이프 방법이 잘못된 것입니다. 백슬래시 자체도 특수 문자로 처리하기 때문에 백슬래시 자체를 한번 더 이스케이프 해야 합니다. 드디어 요소가 선택됩니다.

 
console.log(document.querySelector('#a\\[a\\]'));
 

 

이스케이프는 잘 되지만 쿼리 선택이 복잡해지고, 특수 용도 문자가 여러 개면 이스케이프 하기가 조금 귀찮아집니다.

그리고 자바스크립트에는 CSS 에스케이프를 위한 내장 메서드를 지원합니다.

CSS 객체의 escape() 메서드를 사용하면 특수 문자를 이스케이프 한 쿼리 선택을 반환받을 수 있습니다.

앞서의 쿼리 선택자는 이스케이프 할 쿼리 선택을 escape() 메서드 인자로 넘겨서 다음과 같이 재작성할 수 있습니다.

 

console.log(document.querySelector("#"+CSS.escape("a[a]")));
 
쿼리 선택과 함께 "#", "." 과 같은 별도의 문자열을 붙이는 것이 조금 번거롭고, 코드의 가독성도 떨어집니다. 그래서 백쿼트(`)를 이용해서 다음과 같이 템플릿 문자열로 표현할 수 있습니다.

 

console.log(document.querySelector(`#${CSS.escape("a[a]")}`));