DOM 조작 마스터하기: 웹 페이지를 동적으로 제어하는 모든 방법 (초보자 가이드)
웹사이트에 접속했을 때, 버튼을 클릭하면 내용이 바뀌고, 이미지가 슬라이드 되거나, 새로운 목록이 추가되는 것을 보셨을 거예요. 이런 모든 동적인 변화는 바로 DOM 조작을 통해 이루어집니다. 웹 개발에서 JavaScript를 이용해 웹 페이지를 자유자재로 움직이게 만들려면 DOM 조작은 필수적인 기술입니다.
이번 포스팅에서는 DOM이 무엇인지부터 시작해서, 자바스크립트로 DOM을 선택하고, 내용을 바꾸고, 요소를 추가하거나 삭제하는 등 웹 페이지를 동적으로 제어하는 모든 기본적인 방법을 초보자도 쉽게 이해할 수 있도록 자세히 설명해 드릴게요.
🌳 DOM(Document Object Model)이란 무엇인가요?
DOM은 Document Object Model의 약자로, 우리말로는 '문서 객체 모델'이라고 부릅니다. 쉽게 말해, 웹 브라우저가 HTML 문서를 이해하기 쉽도록 나무(Tree) 형태의 구조로 만든 모델이에요. 이 모델 덕분에 JavaScript는 HTML 문서의 모든 요소(태그, 속성, 텍스트 등)에 접근하고, 수정하고, 추가하거나 삭제할 수 있게 됩니다.
HTML 문서의 모든 것은 DOM 트리의 '노드(Node)'가 됩니다. 예를 들어, <body>
태그는 하나의 요소 노드이고, 그 안에 있는 <p>
태그도 요소 노드입니다. <p>
태그 안의 텍스트는 텍스트 노드가 되죠.
<!-- HTML 코드 -->
<div id="container">
<h1>안녕하세요!</h1>
<p class="greeting">환영합니다.</p>
</div>
위 HTML 코드는 DOM 트리로 다음과 같이 표현됩니다.
- Document (최상위)
- html
- head
- body
- div (id="container")
- h1 ("안녕하세요!" 텍스트 노드 포함)
- p (class="greeting", "환영합니다." 텍스트 노드 포함)
이렇게 HTML 문서를 객체(Object)들의 모델로 만들어주기 때문에, 우리는 JavaScript를 이용해 이 객체들을 조작해서 웹 페이지를 바꿀 수 있는 것입니다.
🔎 DOM 요소 선택하기
DOM을 조작하려면 먼저 어떤 HTML 요소를 바꿀지 '선택'해야 합니다. JavaScript는 다양한 방법으로 DOM 요소를 선택하는 기능을 제공합니다.
1. ID로 선택하기: getElementById()
HTML 요소에 부여된 고유한 ID를 사용하여 요소를 선택합니다. ID는 웹 페이지에서 하나만 존재해야 합니다.
<!-- HTML -->
<div id="myDiv">안녕하세요!</div>
// JavaScript
const myDiv = document.getElementById('myDiv');
console.log(myDiv); // <div id="myDiv">안녕하세요!</div>
2. CSS 선택자로 선택하기: querySelector()
, querySelectorAll()
CSS에서 요소를 선택하는 방식(태그 이름, 클래스, ID, 속성 등)과 동일하게 CSS 선택자(Selector)를 사용하여 요소를 선택합니다.
querySelector()
: 주어진 선택자에 해당하는 첫 번째 요소 하나만 반환합니다.
querySelectorAll()
: 주어진 선택자에 해당하는 모든 요소들을 배열처럼 생긴 목록(NodeList)으로 반환합니다.
<!-- HTML -->
<p class="item">항목 1</p>
<p class="item">항목 2</p>
<span>스팬 태그</span>
// JavaScript
const firstItem = document.querySelector('.item'); // 첫 번째 <p class="item">
console.log(firstItem); // <p class="item">항목 1</p>
const allItems = document.querySelectorAll('.item'); // 모든 <p class="item">
console.log(allItems); // NodeList(<p.item>, <p.item>)
const spanTag = document.querySelector('span'); // 첫 번째 <span>
console.log(spanTag); // <span>스팬 태그</span>
3. 클래스 이름으로 선택하기: getElementsByClassName()
특정 클래스 이름을 가진 모든 요소를 HTMLCollection 형태로 반환합니다.
const itemsByClass = document.getElementsByClassName('item');
console.log(itemsByClass); // HTMLCollection(p.item, p.item)
4. 태그 이름으로 선택하기: getElementsByTagName()
특정 태그 이름을 가진 모든 요소를 HTMLCollection 형태로 반환합니다.
const allParagraphs = document.getElementsByTagName('p');
console.log(allParagraphs); // HTMLCollection(p.item, p.item)
💡 팁: querySelector()
와 querySelectorAll()
이 가장 강력하고 유연합니다. 대부분의 상황에서 이 두 가지를 주로 사용하게 될 것입니다.
✍️ DOM 요소의 내용 변경하기
요소를 선택했다면, 이제 그 안의 내용을 바꿔볼 수 있습니다.
1. 텍스트 내용 변경: textContent
요소 내부의 텍스트 콘텐츠만 가져오거나 설정합니다. HTML 태그는 무시하고 순수한 텍스트로만 처리합니다.
<!-- HTML -->
<p id="myParagraph">원래 텍스트.</p>
// JavaScript
const paragraph = document.getElementById('myParagraph');
paragraph.textContent = '새로운 텍스트로 바뀌었어요!';
console.log(paragraph.textContent); // "새로운 텍스트로 바뀌었어요!"
2. HTML 내용 변경: innerHTML
요소 내부의 HTML 콘텐츠를 가져오거나 설정합니다. 새로운 HTML 태그를 포함하여 삽입할 수 있습니다.
<!-- HTML -->
<div id="contentDiv">원래 내용.</div>
// JavaScript
const contentDiv = document.getElementById('contentDiv');
contentDiv.innerHTML = '<h3>새로운 제목</h3><p>동적으로 추가된 문단입니다.</p>';
// 이제 contentDiv 안에는 와
태그가 생깁니다.
⚠️ 주의: innerHTML
은 편리하지만, 사용자에게서 입력받은 값을 그대로 사용하면 XSS(Cross-Site Scripting) 공격에 취약해질 수 있으니 주의해야 합니다.
➕➖ DOM 요소 추가 및 삭제하기
웹 페이지에 새로운 요소를 만들거나, 기존 요소를 없애는 방법입니다.
1. 새 요소 만들기: createElement()
새로운 HTML 태그 요소를 메모리상에 만듭니다. 아직 웹 페이지에는 나타나지 않습니다.
// <li> 태그를 만듭니다.
const newListItem = document.createElement('li');
// <p> 태그를 만듭니다.
const newParagraph = document.createElement('p');
2. 텍스트 노드 만들기: createTextNode()
텍스트만을 위한 노드를 만듭니다. 텍스트를 요소에 추가할 때 사용합니다.
const textNode = document.createTextNode('새로운 목록 항목');
// 이 텍스트 노드를 위에서 만든 newListItem에 추가할 수 있습니다.
3. 요소에 자식 추가: appendChild()
부모 요소의 가장 마지막 자식으로 새로운 요소를 추가합니다.
<!-- HTML -->
<ul id="myList">
<li>기존 항목 1</li>
</ul>
// JavaScript
const myList = document.getElementById('myList');
const newListItem = document.createElement('li'); // <li> 생성
newListItem.textContent = '새로운 항목 추가!'; // 텍스트 설정
myList.appendChild(newListItem); // myList의 마지막에 newListItem 추가
// 결과:
4. 요소 삭제: removeChild()
부모 요소에서 특정 자식 요소를 삭제합니다.
// JavaScript
const myList = document.getElementById('myList');
const firstItem = myList.querySelector('li'); // 첫 번째 <li> 선택
myList.removeChild(firstItem); // myList에서 firstItem 삭제
// 결과: (남아있는 li가 없다면)
5. 요소 교체: replaceChild()
부모 요소의 특정 자식 요소를 새로운 요소로 교체합니다.
const parent = document.getElementById('container'); // 부모 요소
const oldChild = document.querySelector('h1'); // 교체될 기존 자식
const newChild = document.createElement('h2'); // 새로 들어올 자식
newChild.textContent = '새로운 제목입니다';
parent.replaceChild(newChild, oldChild); // oldChild를 newChild로 교체
6. 요소 삽입: insertBefore()
, prepend()
insertBefore(newNode, referenceNode)
: 특정 참조 노드 앞에 새로운 노드를 삽입합니다.
prepend(node)
: 부모 요소의 가장 첫 번째 자식으로 새로운 노드를 삽입합니다. (appendChild
의 반대)
<!-- HTML -->
<ul id="myList">
<li id="second">두 번째 항목</li>
<li>세 번째 항목</li>
</ul>
// JavaScript
const myList = document.getElementById('myList');
const secondItem = document.getElementById('second');
// insertBefore 사용 예시: '두 번째 항목' 앞에 '첫 번째 항목' 삽입
const firstListItem = document.createElement('li');
firstListItem.textContent = '가운데 삽입된 항목';
myList.insertBefore(firstListItem, secondItem);
// 결과:
// prepend 사용 예시: '가장 첫 번째 항목' 삽입
const topListItem = document.createElement('li');
topListItem.textContent = '가장 첫 번째 항목';
myList.prepend(topListItem);
// 결과: - 가장 첫 번째 항목
- 가운데 삽입된 항목
- 두 번째 항목
- 세 번째 항목
⚙️ DOM 요소의 속성과 스타일 변경하기
HTML 태그의 속성(예: src
, href
, class
, id
)이나 CSS 스타일을 변경하는 방법입니다.
1. 속성 제어: setAttribute()
, getAttribute()
, removeAttribute()
setAttribute(name, value)
: 요소의 속성 값을 설정하거나, 새로운 속성을 추가합니다.
getAttribute(name)
: 요소의 특정 속성 값을 가져옵니다.
removeAttribute(name)
: 요소의 특정 속성을 삭제합니다.
<!-- HTML -->
<img id="myImage" src="default.png" alt="기본 이미지">
<a id="myLink" href="#">링크</a>
// JavaScript
const myImage = document.getElementById('myImage');
const myLink = document.getElementById('myLink');
// 이미지 src 변경
myImage.setAttribute('src', 'new_image.png');
// 이미지 alt 값 가져오기
console.log(myImage.getAttribute('alt')); // "기본 이미지"
// 링크 href 변경 및 target 속성 추가
myLink.setAttribute('href', 'https://www.google.com');
myLink.setAttribute('target', '_blank'); // 새 탭에서 열기
// alt 속성 삭제
myImage.removeAttribute('alt');
2. 스타일 변경: style
속성 및 classList
요소의 CSS 스타일을 변경하는 방법입니다.
-
.style
속성: 개별 CSS 속성 직접 변경
JavaScript에서 CSS 속성 이름을 사용할 때는 하이픈(-) 대신 카멜 케이스(camelCase)를 사용합니다. (예: `background-color` -> `backgroundColor`)
const myDiv = document.getElementById('myDiv');
myDiv.style.backgroundColor = 'blue';
myDiv.style.color = 'white';
myDiv.style.fontSize = '20px';
-
.classList
속성: 클래스 추가/삭제 (권장!)
요소의 클래스 이름을 추가하거나 제거하는 방식으로 스타일을 제어하는 것이 더 효율적이고 유지보수하기 좋습니다. 미리 CSS에 스타일 규칙을 정의해두고 JavaScript로 클래스를 토글하는 방식입니다.
add('클래스명')
: 클래스 추가
remove('클래스명')
: 클래스 삭제
toggle('클래스명')
: 클래스가 있으면 삭제, 없으면 추가 (스위치 기능에 유용)
contains('클래스명')
: 해당 클래스가 있는지 확인 (true/false 반환)
<!-- HTML -->
<button id="myButton" class="default-btn">클릭하세요</button>
<!-- CSS -->
<style>
.default-btn { background-color: lightgray; color: black; padding: 10px; }
.active-btn { background-color: blue; color: white; border: none; }
</style>
// JavaScript
const myButton = document.getElementById('myButton');
myButton.addEventListener('click', () => {
// 'active-btn' 클래스를 토글 (있으면 제거, 없으면 추가)
myButton.classList.toggle('active-btn');
if (myButton.classList.contains('active-btn')) {
console.log('버튼이 활성화 상태입니다.');
} else {
console.log('버튼이 비활성화 상태입니다.');
}
});
⚡ 이벤트 핸들링의 기초: addEventListener()
사용자가 버튼을 클릭하거나, 마우스를 올리거나, 키보드를 누르는 등 특정 행동을 했을 때 JavaScript 코드를 실행하려면 이벤트 핸들링(Event Handling)이 필요합니다. addEventListener()
메서드를 가장 많이 사용합니다.
// JavaScript
const myButton = document.getElementById('myButton');
// 'myButton'을 클릭하면 메시지를 띄우는 이벤트 리스너 추가
myButton.addEventListener('click', () => {
alert('버튼이 클릭되었습니다!');
});
// 'myInput'에 키보드를 누를 때마다 콘솔에 입력된 값 출력
const myInput = document.getElementById('myInput');
myInput.addEventListener('keyup', (event) => {
console.log('현재 입력 값:', event.target.value);
});
💡 DOM 조작 시 성능 팁 (간단히)
DOM 조작은 웹 페이지 성능에 영향을 줄 수 있습니다. 특히 많은 요소를 자주 조작할 때는 주의해야 합니다.
- 최소한의 DOM 조작: 여러 개의 요소를 만들거나 수정해야 할 때, 각 요소를 개별적으로 페이지에 추가하기보다는, 먼저 메모리상에서 모든 작업을 완료한 후 한 번에 페이지에 삽입하는 것이 효율적입니다. (예: `DocumentFragment` 사용)
innerHTML
남용 주의: 큰 HTML 문자열을 `innerHTML`로 설정하면 기존 내용을 모두 파싱하고 새로 그리는 과정에서 성능 저하가 올 수 있습니다. 꼭 필요한 경우에만 사용하거나, `textContent`를 선호하세요.
classList
활용: `style` 속성을 직접 변경하기보다는 CSS 클래스를 추가/제거하는 것이 성능과 유지보수 면에서 더 좋습니다.
✨ 결론
DOM 조작은 웹 페이지를 동적이고 상호작용적인 공간으로 만드는 핵심 기술입니다. HTML 문서를 JavaScript가 이해할 수 있는 트리 형태로 바꾸는 DOM의 개념을 이해하고, 요소를 선택하고, 내용을 바꾸고, 추가하거나 삭제하는 다양한 메서드를 익히는 것은 모든 웹 개발자에게 필수적입니다.
이 포스팅에서 다룬 기본적인 DOM 조작 방법들을 잘 익히시면, 이제 여러분의 웹 페이지에 생명을 불어넣고 사용자들에게 더욱 풍부한 경험을 제공할 수 있을 것입니다. 지금 바로 직접 코드를 작성하며 DOM 조작의 재미를 느껴보세요!