Ver2.5 자바스크립트, 브라우저를 지배하는 열쇠 🔑Web API 완전 정복 (DOM, BOM, CSSOM)

자바스크립트, 브라우저를 지배하는 열쇠 🔑
Web API 완전 정복 (DOM, BOM, CSSOM)
안녕! 코딩의 세계에 막 발을 들였거나, 혹은 자바스크립트(JavaScript)의 깊은 맛을 더 느끼고 싶은 너에게 이 글을 바쳐. 😎
우리가 자바스크립트를 배울 때, 흔히 '언어' 자체의 문법(변수, 함수, 반복문 같은 거)에 집중하잖아? 근데 그거 알아? 순수한 자바스크립트는 사실 '말'만 할 줄 아는 똑똑한 아기 같은 존재야. 혼자서는 아무것도 못 해. 그림을 그리거나, 창문을 열거나, 가구를 옮기는 능력은 없어.
그럼 우리가 맨날 보는 웹사이트의 화려한 애니메이션, 버튼 클릭하면 뿅 하고 나타나는 팝업창, 스크롤 내리면 스르륵 등장하는 콘텐츠들은 다 어떻게 만드는 걸까?
바로 자바스크립트가 '브라우저'라는 엄청난 능력자를 조종하기 때문이야. 그리고 이 조종을 가능하게 해주는 리모컨이 바로 **Web API**라는 거지.
생각해봐. 네가 엄청난 영화감독(자바스크립트)이야. 네 머릿속엔 기가 막힌 스토리가 있어. 하지만 배우(HTML 요소)들한테 연기 지시를 내리고, 카메라(브라우저 창) 앵글을 바꾸고, 조명(CSS 스타일)을 조절하려면 '확성기'나 '무전기' 같은 도구가 필요하겠지? Web API가 바로 그 역할을 해.
오늘은 이 Web API의 핵심 삼대장, **DOM, BOM, CSSOM**에 대해 아주 탈탈 털어볼 거야. 이 세 가지만 제대로 이해해도, 넌 더 이상 자바스크립트 '문법'만 아는 초보가 아니라, 브라우저라는 거대한 무대를 자유자재로 주무르는 '연출가'가 될 수 있어. 준비됐어? 그럼, 지금부터 시작하자!
DOM: 웹 페이지의 설계도를 펼쳐라! 📜
첫 번째 주인공은 **DOM(Document Object Model)**이야. 번역하면 '문서 객체 모델'. 이름부터 뭔가 딱딱하지?
쉽게 말해줄게. 우리가 보는 웹 페이지는 사실 ``, `
이때 브라우저는 그냥 텍스트를 그림으로 뿅! 하고 바꾸는 게 아니야. 먼저 이 HTML 문서를 **자바스크립트가 이해할 수 있는 '객체(Object)' 형태로 바꿔서 메모리에 저장**해. 마치 레고 설명서를 보고, 하나하나 부품을 조립해서 거대한 모델을 만드는 것처럼 말이야. 이렇게 만들어진 객체 모델이 바로 DOM이야.
DOM은 '트리(Tree)' 구조를 하고 있어. 가장 꼭대기에 `document` 객체가 있고, 그 아래로 ``, `
`, `` 같은 태그들이 나뭇가지처럼 뻗어 나가는 형태지. 모든 HTML 태그, 태그 안의 텍스트, 심지어 주석까지 전부 각각의 '노드(Node)'라는 객체가 되어서 이 트리를 구성해.
자, 그럼 이 DOM으로 뭘 할 수 있을까? **거의 모든 것.**
자바스크립트는 이 DOM API를 통해 웹 페이지의 모든 요소에 접근하고, 내용을 바꾸고, 스타일을 입히고, 심지어 없던 요소를 새로 만들거나 기존 요소를 삭제할 수도 있어. 우리가 아는 '동적인 웹'은 전부 이 DOM 조작을 통해 이루어지는 거야.
1. DOM 요소에 접근하기 (feat. 쿼리)
DOM을 조작하려면 먼저 원하는 요소를 '선택'해야겠지? 마치 리모컨으로 특정 채널을 고르는 것처럼 말이야. 자바스크립트는 다양한 방법을 제공해.
`document.getElementById('아이디')`
가장 클래식하고 빠른 방법. HTML에서 `id` 속성은 페이지 내에서 유일해야 하거든. 그래서 특정 요소 하나를 콕 집어서 가져올 때 아주 유용해.
// HTML: <div id="hero">나는 영웅!</div>
const heroElement = document.getElementById('hero');
console.log(heroElement); // <div id="hero">...</div> 객체를 반환
`document.getElementsByClassName('클래스명')`
이름에 'Elements'(복수형)가 들어간 걸 주목해. 클래스는 여러 요소가 함께 가질 수 있잖아? 그래서 이 메서드는 해당 클래스를 가진 모든 요소를 `HTMLCollection`이라는 *유사 배열*에 담아서 반환해.
// HTML: <p class="item">항목1</p>, <p class="item">항목2</p>
const items = document.getElementsByClassName('item');
console.log(items); // HTMLCollection [p.item, p.item]
console.log(items[0]); // 첫 번째 p 태그에 접근 가능
`document.querySelector('CSS 선택자')`
현대 자바스크립트의 구세주! CSS 선택자 문법을 그대로 쓸 수 있어서 정말 강력하고 편리해. `#id`, `.class`, `div > p` 같은 복잡한 선택도 가능하지. 단, 조건에 맞는 **첫 번째 요소 하나만** 반환해.
const firstItem = document.querySelector('.item'); // 클래스가 'item'인 첫 번째 요소
const heroAgain = document.querySelector('#hero'); // 아이디가 'hero'인 요소
`document.querySelectorAll('CSS 선택자')`
`querySelector`의 형제. 이름처럼 조건에 맞는 **모든 요소를 `NodeList`**라는 유사 배열에 담아서 반환해. `getElementsByClassName`과 비슷하지만, `NodeList`는 대부분의 경우 '살아있지 않은(static)' 컬렉션이야. 즉, DOM이 바뀌어도 `NodeList` 변수의 내용은 자동으로 업데이트되지 않아. 대신 `forEach`를 쓸 수 있어서 훨씬 편해!
const allItems = document.querySelectorAll('.item');
allItems.forEach(item => {
console.log(item.textContent);
});
// 출력:
// 항목1
// 항목2
2. DOM 조작하기 (feat. 창조와 변화)
자, 이제 원하는 요소를 선택했으니 마음껏 요리해볼 시간이야.
요소 생성 및 추가
없던 HTML 요소를 자바스크립트로 만들어서 페이지에 붙일 수 있어.
// 1. 새로운 <li> 요소를 만든다.
const newLi = document.createElement('li');
// 2. 텍스트를 추가한다.
newLi.textContent = '새로운 항목!';
// 3. 페이지의 <ul> 태그를 찾아서...
const ul = document.querySelector('ul');
// 4. 그 자식으로 <li>를 추가한다.
ul.appendChild(newLi);
내용 변경: `innerHTML` vs `textContent` vs `innerText`
이 셋은 정말 중요해서 꼭 구분해야 해.
- `innerHTML`: HTML 태그를 **인식**해서 내용을 갈아 끼워. 편리하지만, 사용자가 입력한 값을 그대로 넣으면 `script` 태그 등을 이용한 **XSS(Cross-Site Scripting) 공격**에 취약해질 수 있으니 조심해야 해.
- `textContent`: 순수하게 **텍스트**만 다뤄. HTML 태그를 넣어도 그냥 문자열로 취급해버리지. 빠르고 안전해서 텍스트만 바꿀 땐 이게 최고야.
- `innerText`: `textContent`랑 비슷한데, 약간 더 똑똑해. 화면에 **보이는(rendered)** 텍스트만 가져와. 예를 들어 `display: none;`으로 숨겨진 텍스트는 가져오지 않아. 이 '계산' 과정 때문에 `textContent`보다 조금 느릴 수 있어.
const myDiv = document.querySelector('#my-div');
myDiv.innerHTML = '<strong>중요!</strong>'; // 화면에 '중요!'가 굵게 표시됨
myDiv.textContent = '<strong>중요!</strong>'; // 화면에 '<strong>중요!</strong>' 글자가 그대로 보임
속성(Attribute)과 스타일 변경
`setAttribute`, `getAttribute`로 HTML 속성을 바꾸거나, `element.style` 프로퍼티로 CSS 스타일을 직접 바꿀 수 있어.
const link = document.querySelector('a');
// href 속성 변경
link.setAttribute('href', 'https://www.jaenung.net');
// style 속성을 직접 조작 (인라인 스타일로 들어감)
link.style.color = 'blue';
link.style.fontSize = '20px'; // CSS의 font-size는 JS에서 카멜케이스(camelCase)로!
3. DOM 이벤트: 사용자와의 소통
DOM의 꽃은 바로 **이벤트(Event)**야. 사용자가 버튼을 클릭하거나, 마우스를 움직이거나, 키보드를 누르는 모든 행동이 '이벤트'가 되어 자바스크립트에 신호를 보내. 우리는 이 신호를 받아서 특정 동작을 실행시킬 수 있지.
`addEventListener`
이벤트 처리는 `element.onclick = function() {}` 처럼 할 수도 있지만, 현대적인 방식은 `addEventListener`를 쓰는 거야. 하나의 이벤트(예: 'click')에 여러 개의 함수를 연결할 수 있는 등 훨씬 유연하거든.
const myButton = document.querySelector('#my-button');
function handleClick() {
alert('버튼이 클릭되었어요!');
}
myButton.addEventListener('click', handleClick);
- **Reflow(리플로우) 또는 Layout(레이아웃):** 요소의 크기나 위치 같은 기하학적인 속성이 바뀌었을 때 발생해. 레이아웃 계산을 다시 해야 해서 비용이 아주 비싸. 예를 들어, 요소의 `width`를 바꾸거나, DOM에 요소를 추가/삭제하는 경우.
- **Repaint(리페인트) 또는 Redraw(리드로우):** 레이아웃에 영향을 주지 않는, 색상이나 배경 같은 시각적 스타일만 바뀔 때 발생해. Reflow보다는 부담이 적어.
똑똑한 개발자는 이 Reflow를 최소화하려고 노력해. 예를 들어, 여러 스타일을 한 번에 바꾸고 싶을 때, `element.style.left`, `element.style.top`을 각각 바꾸는 것보다, 미리 정의된 클래스를 한 번에 `element.classList.add('new-position')` 하는 식으로 바꾸는 게 훨씬 효율적이야.
BOM: 브라우저 자체를 조종하는 마법 🪄
DOM이 웹 페이지 '내용'의 설계도였다면, **BOM(Browser Object Model)**은 그 페이지를 담고 있는 '브라우저 창' 자체를 조종하는 리모컨이야.
BOM은 DOM처럼 표준화된 명세가 없어. 그래서 브라우저마다 조금씩 다를 수 있지만, 대부분 공통적으로 지원하는 핵심 객체들이 있어. 그리고 이 모든 BOM 객체들의 정점에는 `window` 객체가 있어. 사실 우리가 `alert()`, `setTimeout()` 같은 함수들을 `window.` 없이 그냥 쓰는 이유도, `window`가 브라우저 환경의 **전역 객체(Global Object)**이기 때문이야. `document` 객체도 사실은 `window.document`인 셈이지.
1. `window` 객체: 모든 것의 시작
`window` 객체는 현재 브라우저 창이나 탭 그 자체를 의미해. 창의 크기를 얻거나, 새 창을 띄우거나, 경고창을 보여주는 등 다양한 일을 할 수 있어.
// 현재 창의 내부 너비와 높이
console.log(window.innerWidth, window.innerHeight);
// 경고창, 확인창, 입력창
alert('경고!');
const isOkay = confirm('계속할까요?');
const userName = prompt('이름을 입력하세요');
// 새 창 열기
window.open('https://www.google.com');
2. `location` 객체: URL의 모든 것
현재 페이지의 URL 정보를 담고 있고, 페이지를 이동시키는 기능도 해.
// 현재 페이지의 전체 URL
console.log(location.href);
// 다른 페이지로 이동하기
location.href = 'https://www.naver.com';
// location.assign('https://www.naver.com'); // 위와 동일
// 페이지 새로고침
location.reload();
// 히스토리에 남기지 않고 페이지 이동 (뒤로가기 불가)
// location.replace('https://www.naver.com');
3. `history` 객체: 시간 여행자
브라우저의 방문 기록(세션 히스토리)을 조작할 수 있어. 보안상의 이유로 정확히 어떤 URL을 방문했는지는 알 수 없고, 앞/뒤로 이동만 가능해.
// 뒤로 가기
history.back();
// 앞으로 가기
history.forward();
// 2페이지 뒤로 가기
history.go(-2);
4. `navigator` 객체: 브라우저 탐정
사용자가 어떤 브라우저를 쓰는지, 어떤 언어를 설정했는지, 온라인 상태인지 등의 정보를 담고 있어.
// 브라우저 정보가 담긴 User Agent 문자열
console.log(navigator.userAgent);
// 브라우저 기본 언어
console.log(navigator.language);
// 온라인 상태 확인
console.log(navigator.onLine); // true 또는 false
5. 타이머: 시간의 마법사
BOM의 일부인 타이머 함수들은 비동기 프로그래밍의 기초를 이루는 아주 중요한 기능이야.
- `setTimeout(함수, 시간)`: 지정된 시간(밀리초) 후에 함수를 **한 번** 실행해.
- `setInterval(함수, 시간)`: 지정된 시간마다 함수를 **계속 반복**해서 실행해.
- `clearTimeout(타이머ID)`, `clearInterval(타이머ID)`: 예약된 타이머를 취소해.
console.log('시작!');
const timerId = setTimeout(() => {
console.log('3초가 지났습니다!');
}, 3000);
// 만약 3초가 되기 전에 특정 조건이 만족되면 타이머를 취소할 수 있어.
// clearTimeout(timerId);
let count = 0;
const intervalId = setInterval(() => {
count++;
console.log(`1초마다 실행: ${count}번째`);
if (count >= 5) {
clearInterval(intervalId); // 5번 실행 후 반복을 멈춤
console.log('인터벌 종료!');
}
}, 1000);
CSSOM: 스타일의 비밀을 파헤치다 🎨
자, 이제 마지막 주인공 **CSSOM(CSS Object Model)**이야. 이름에서 감이 오지? DOM이 HTML을 객체로 만든 거라면, CSSOM은 CSS를 객체로 만든 거야.
브라우저는 CSS 파일이나 `
이 과정을 이해하면 왜 CSS를 `
` 태그 안에 넣고, 자바스크립트를 `` 태그가 끝나기 직전에 넣으라고 하는지 알 수 있어. 브라우저가 렌더 트리를 최대한 빨리 만들어서 사용자에게 일단 화면을 보여주고, 그 다음에 스크립트 기능을 로드하는 게 사용자 경험에 더 좋기 때문이지.DOM, BOM, CSSOM: 환상의 오케스트라 🎶
지금까지 우리는 DOM, BOM, CSSOM이라는 세 명의 연주자를 각각 만나봤어. 하지만 이들의 진정한 힘은 함께 연주할 때 나와. 마치 오케스트라처럼 말이야.
- **BOM**은 지휘자(`window`)가 전체 공연장(브라우저)을 통제하고, 공연 시간을 조율(`setTimeout`)하는 것과 같아.
- **DOM**은 무대 위의 배우(HTML 요소)들이 대본(DOM Tree)에 따라 움직이고, 소품을 사용하고, 서로 상호작용하는 것과 같지.
- **CSSOM**은 조명팀이 배우들에게 스포트라이트(스타일)를 비추고, 무대 배경을 바꾸는 것과 같아.
이 모든 것이 자바스크립트라는 총감독의 지휘 아래 완벽한 하모니를 이루면서 우리가 경험하는 '인터랙티브 웹'이라는 멋진 공연이 탄생하는 거야.
실전 예제: 다크 모드 토글 버튼 만들기
이 모든 개념을 한 번에 이해할 수 있는 최고의 예제는 바로 '다크 모드' 기능이야. 한번 상상하며 따라와 봐.
<!-- HTML -->
<body>
<h1>안녕하세요!</h1>
<p>라이트 모드입니다.</p>
<button id="theme-toggle">다크 모드로 변경</button>
</body>
/* CSS */
body {
transition: background-color 0.3s, color 0.3s;
}
body.dark-mode {
background-color: #121212;
color: #ffffff;
}
body.dark-mode p {
color: #bbbbbb;
}
// JavaScript
// 1. 필요한 DOM 요소들을 선택한다. (DOM API)
const body = document.querySelector('body');
const toggleButton = document.querySelector('#theme-toggle');
const pTag = document.querySelector('p');
// 2. 버튼 클릭 이벤트를 감지한다. (DOM Event)
toggleButton.addEventListener('click', () => {
// 3. body에 'dark-mode' 클래스가 있는지 확인하고, 없으면 추가, 있으면 제거한다. (DOM 조작)
body.classList.toggle('dark-mode');
// 4. 현재 상태에 따라 버튼 텍스트와 p 태그 내용을 변경한다. (BOM, DOM 조작)
const isDarkMode = body.classList.contains('dark-mode');
if (isDarkMode) {
toggleButton.textContent = '라이트 모드로 변경';
pTag.textContent = '다크 모드입니다.';
// 로컬 스토리지에 상태 저장 (BOM - Web Storage API)
localStorage.setItem('theme', 'dark');
} else {
toggleButton.textContent = '다크 모드로 변경';
pTag.textContent = '라이트 모드입니다.';
localStorage.setItem('theme', 'light');
}
});
// 5. 페이지 로드 시 저장된 테마를 적용한다. (BOM, DOM)
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
// 가상으로 클릭 이벤트를 발생시켜 상태를 동기화
toggleButton.click();
}
이 간단한 예제 안에 우리가 배운 모든 것이 녹아있어.
- **DOM:** `querySelector`, `addEventListener`, `classList.toggle`, `textContent`를 사용해서 페이지의 구조와 내용을 바꿨어.
- **BOM:** `localStorage`라는 Web Storage API(BOM의 일부로 취급되기도 함)를 사용해서 사용자의 테마 선택을 브라우저에 저장했지. 덕분에 페이지를 새로고침해도 다크 모드가 유지돼.
- **CSSOM:** 자바스크립트가 `dark-mode` 클래스를 ``에 추가하자, 브라우저는 이 변화를 감지하고 CSSOM을 업데이트했어. 그리고 새로운 스타일 규칙(`body.dark-mode`)을 렌더 트리에 적용해서 화면을 다시 그렸지(Repaint).
마치며: 기본기의 중요성
요즘은 React, Vue, Svelte 같은 멋진 프레임워크들이 많아서 우리가 직접 DOM을 조작할 일이 예전보다 줄어든 건 사실이야. 이 프레임워크들은 '가상 DOM(Virtual DOM)' 같은 기술을 써서 더 효율적으로 화면을 업데이트해주거든.
하지만! 이 프레임워크들도 결국 내부에서는 오늘 우리가 배운 DOM, BOM, CSSOM API를 사용해서 브라우저와 소통해. 그래서 이 기본 원리를 이해하는 건 정말 중요해. 자동차 운전법을 배웠다고 해서 자동차 엔진의 원리를 알 필요는 없지만, 카레이서가 되려면 엔진을 이해해야 하는 것과 같아. 웹 성능을 최적화하거나, 복잡한 버그를 디버깅하거나, 프레임워크 없이 순수한 자바스크립트로 무언가를 만들어야 할 때, 이 지식은 너의 가장 강력한 무기가 될 거야.
이런 깊이 있는 지식을 바탕으로 자신만의 웹 프로젝트를 만들어보거나, **재능넷** 같은 플랫폼에서 여러분의 개발 실력을 필요로 하는 사람들을 도와주며 경험을 쌓아보는 건 어떨까? 이론을 실제로 적용해보는 것만큼 좋은 공부는 없으니까 말이야.
오늘 정말 긴 여정이었지만, 여기까지 따라온 너는 이제 자바스크립트로 브라우저를 지배할 수 있는 열쇠를 손에 쥔 거야. 축하해! 앞으로 너의 코드가 만들어낼 놀라운 웹의 세계를 기대할게. 화이팅! 🚀
댓글 작성
이 글에 대한 여러분의 생각을 들려주세요
로그인이 필요합니다
댓글을 작성하려면 먼저 로그인해주세요.
댓글 0
지식인의 숲 - 지적 재산권 보호 고지
지적 재산권 보호 고지
- 저작권 및 소유권: 본 컨텐츠는 재능넷의 독점 AI 기술로 생성되었으며, 대한민국 저작권법 및 국제 저작권 협약에 의해 보호됩니다.
- AI 생성 컨텐츠의 법적 지위: 본 AI 생성 컨텐츠는 재능넷의 지적 창작물로 인정되며, 관련 법규에 따라 저작권 보호를 받습니다.
- 사용 제한: 재능넷의 명시적 서면 동의 없이 본 컨텐츠를 복제, 수정, 배포, 또는 상업적으로 활용하는 행위는 엄격히 금지됩니다.
- 데이터 수집 금지: 본 컨텐츠에 대한 무단 스크래핑, 크롤링, 및 자동화된 데이터 수집은 법적 제재의 대상이 됩니다.
- AI 학습 제한: 재능넷의 AI 생성 컨텐츠를 타 AI 모델 학습에 무단 사용하는 행위는 금지되며, 이는 지적 재산권 침해로 간주됩니다.
아직 댓글이 없습니다.