JavaScript / querySelector()로 CSS 선택자에 맞는 첫 요소 선택하기
document.querySelector(selector)는 CSS 선택자와 일치하는 첫 번째 요소 하나를 반환합니다. 일치하는 요소가 없으면 null, 선택자 문법이 잘못되면 SyntaxError 예외가 발생합니다. 여러 요소 중 하나만 바꾸려는 경우와 모든 요소를 처리해야 하는 경우를 구분해 사용하세요.
첫 번째 일치 요소 선택하기
선택자는 CSS에서 쓰는 문법 그대로 문자열로 전달합니다. .target은 클래스를, #panel은 ID를 뜻합니다. 같은 클래스를 가진 요소가 여러 개라면 문서 순서상 첫 번째 요소만 가져옵니다.
const first = document.querySelector('.target');
if (first !== null) {
first.textContent = '첫 항목';
}
위 코드는 first가 실제 요소인지 확인한 뒤 내용을 바꿉니다. 확인 없이 document.querySelector(".missing").textContent를 읽으면 null의 속성을 읽으려다 오류가 납니다. MDN의 Document.querySelector() 문서에서 반환값과 탐색 순서를 확인할 수 있습니다.
범위를 좁히는 복합 선택자
#panel .target은 ID가 panel인 요소 안쪽의 .target을 뜻합니다. 구역 밖에도 .target이 있다면 .target만으로는 그 바깥 요소가 먼저 선택될 수 있습니다. 필요한 부모 요소와의 관계까지 지정하면 의도한 구역을 찾을 수 있습니다.
const firstAnywhere = document.querySelector('.target');
const firstInPanel = document.querySelector('#panel .target');
console.log(firstAnywhere?.textContent); // 문서의 첫 대상
console.log(firstInPanel?.textContent); // panel 안의 첫 대상
이미 부모 요소를 변수로 가지고 있다면 그 요소의 querySelector()로 자손을 검색할 수도 있습니다. 현재 문서에서 여러 일치를 한꺼번에 처리해야 한다면 querySelectorAll()이 적합합니다. querySelector()로 얻은 요소 한 개는 컬렉션이 아니므로 [0]을 붙이지 않습니다.
없음과 잘못된 선택자 구분하기
정상적인 선택자라도 일치가 없으면 null입니다. 반면 "???"처럼 CSS 문법에 맞지 않는 선택자는 SyntaxError를 던집니다. 외부 입력으로 선택자를 만들 때는 이 둘을 별도로 처리하고, ID·클래스 값에 CSS 문법상 특수 문자가 있다면 CSS.escape()를 검토하세요.
document.querySelector('.missing'); // null
try {
document.querySelector('???');
} catch (error) {
console.log(error.name); // 'SyntaxError'
}
검색 시점도 중요합니다. 요소가 만들어지기 전에 스크립트가 실행되면 올바른 선택자여도 null이 나올 수 있습니다. 스크립트를 문서 끝에 두거나 외부 파일에 defer를 사용해 HTML 해석 뒤에 실행하세요.
전체 예제: 첫 요소와 오류 결과 비교
다음 코드를 UTF-8의 query-selector-example.html로 저장해 브라우저에서 엽니다. 선택자를 바꿔 ‘찾기’를 누르면 선택된 한 요소가 강조됩니다. 일치 없음과 문법 오류의 차이도 같은 화면에서 확인할 수 있습니다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>첫 번째 CSS 선택자 결과</title>
<style>.selected { background: #fff2a8; outline: 2px solid #a76b00; }</style>
</head>
<body>
<h1>첫 번째 요소 선택하기</h1>
<p class="target">바깥 항목</p>
<section id="panel">
<p class="target">패널 첫 항목</p>
<p class="target">패널 둘째 항목</p>
</section>
<label for="selector">CSS 선택자</label>
<select id="selector">
<option value=".target">.target</option>
<option value="#panel .target">#panel .target</option>
<option value=".missing">.missing</option>
<option value="???">???</option>
</select>
<button id="find" type="button">찾기</button>
<button id="reset" type="button">처음으로</button>
<p id="output" aria-live="polite"></p>
<script>
const choice = document.querySelector('#selector');
const output = document.querySelector('#output');
function choose() {
document.querySelector('.selected')?.classList.remove('selected');
try {
const found = document.querySelector(choice.value);
if (found === null) {
output.textContent = '일치하는 요소가 없습니다: null';
return;
}
found.classList.add('selected');
output.textContent = `선택: ${found.textContent.trim()}`;
} catch (error) {
if (error.name === 'SyntaxError') {
output.textContent = '올바르지 않은 CSS 선택자: SyntaxError';
} else {
throw error;
}
}
}
document.querySelector('#find').addEventListener('click', choose);
document.querySelector('#reset').addEventListener('click', () => {
choice.value = '.target';
choose();
});
choose();
</script>
</body>
</html>
기본 .target은 구역 밖의 ‘바깥 항목’을 강조합니다. #panel .target을 고르면 ‘패널 첫 항목’으로 바뀌고 같은 클래스를 가진 ‘패널 둘째 항목’은 강조되지 않습니다. .missing은 null 안내를, ???는 SyntaxError 안내를 보여 줍니다. ‘처음으로’를 누르면 .target 선택과 첫 강조 상태로 되돌아갑니다. 원래 글의 정적 화면 캡처보다 각 경우를 직접 확인하기 쉽습니다.




