Skip to main content
Summary

이제 결과가 화면에 보입니다

지금까지는 대부분 console.log()로 결과를 확인했습니다. 콘솔은 연습장으로 좋지만, 실제 웹사이트를 만드는 목적지는 결국 화면입니다. 사용자가 보는 제목이 바뀌고, 안내 문구가 나타나고, 목록에 새 항목이 추가되는 일이 필요합니다.

이 장부터 자바스크립트는 콘솔 밖으로 나옵니다. HTML로 만든 웹페이지를 자바스크립트가 찾아가고, 필요한 부분을 바꿉니다.

여기서 중요한 관점이 있습니다.

자바스크립트가 HTML과 CSS를 없애고 대신하는 것이 아닙니다. HTML은 여전히 내용과 구조를 맡고, CSS는 모양을 맡습니다. 자바스크립트는 필요한 순간에 HTML과 CSS를 조작합니다. 예를 들어 "로그인 성공"이라는 상황이 생기면 문구를 바꾸고, 특정 상품을 강조하고, 새 알림을 화면에 추가합니다.

웹페이지를 직접 바꾸는 DOM 기초AI 생성 이미지

DOM은 브라우저가 만든 웹페이지 지도입니다

브라우저는 HTML 파일을 그대로 종이에 인쇄하듯 보여 주지 않습니다. 먼저 HTML을 읽고, 화면에서 다룰 수 있는 구조로 바꿉니다. 이 구조를 DOM이라고 합니다.

DOM은 Document Object Model의 줄임말입니다. 이름은 길지만, 처음에는 이렇게 이해하면 됩니다.

DOM은 브라우저가 HTML을 읽고 만든 웹페이지 지도입니다.

예를 들어 이런 HTML이 있다고 해 보겠습니다.

<body>
  <h1>오늘의 할 일</h1>
  <ul>
    <li>메일 확인</li>
    <li>회의 준비</li>
  </ul>
</body>

브라우저는 이 구조를 머릿속에 이런 관계로 정리합니다.

body
├─ h1
└─ ul
   ├─ li
   └─ li

body 안에 h1과 ul이 들어 있습니다. ul 안에는 li가 두 개 들어 있습니다.

이때 body는 h1과 ul의 부모라고 부를 수 있습니다. h1과 ul은 body의 자식입니다. 같은 부모 아래에 나란히 있는 h1과 ul은 형제처럼 볼 수 있습니다.

이 관계를 알아두면 자바스크립트가 화면을 바꾸는 방식이 자연스럽게 보입니다. 자바스크립트는 DOM이라는 지도에서 원하는 요소를 찾고, 그 요소의 글자나 모양을 바꿉니다.

실습용 HTML 파일 만들기

이번 장은 콘솔만으로는 아쉽습니다. 간단한 HTML 파일을 하나 만들고 브라우저에서 열어 보겠습니다.

파일 이름은 dom-practice.html로 저장하세요.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>DOM 연습</title>
  <style>
    .highlight {
      background-color: yellow;
      font-weight: bold;
    }

    .done {
      color: gray;
      text-decoration: line-through;
    }
  </style>
</head>
<body>
  <h1 id="main-title">오늘의 할 일</h1>

  <p class="message">아직 선택된 일이 없습니다.</p>

  <a rel="nofollow ugc noopener" id="help-link" href="https://developer.mozilla.org/ko/">도움말 보기</a>

  <ul id="todo-list">
    <li>메일 확인</li>
    <li>회의 준비</li>
  </ul>
</body>
</html>

파일을 저장한 뒤 브라우저로 열어 보세요. 그리고 개발자 도구의 Console 탭을 엽니다. 이제 콘솔에 입력한 자바스크립트가 실제 페이지를 바꾸는지 확인할 수 있습니다.

한 가지 작은 주의점이 있습니다. 이 장의 예제는 설명을 위해 const title, const message 같은 이름을 여러 번 사용합니다. 콘솔에서 같은 이름을 다시 선언하면 브라우저에 따라 Identifier has already been declared 같은 오류가 날 수 있습니다. 그럴 때는 페이지를 새로고침한 뒤 다시 실행하거나, 이미 만든 변수 선언 줄은 빼고 다음 줄만 실행해도 됩니다.

요소 찾기: querySelector()와 getElementById()

화면을 바꾸려면 먼저 바꿀 대상을 찾아야 합니다. 집 안에서 전등을 켜려면 스위치 위치를 알아야 하는 것과 같습니다.

자바스크립트에서 HTML 요소를 찾을 때 자주 쓰는 방법은 두 가지입니다.

document.querySelector('선택자')
document.getElementById('아이디이름')

document는 현재 웹페이지 문서를 뜻합니다. "이 문서 안에서 찾아라"라는 출발점입니다.

먼저 제목을 찾아 보겠습니다.

const title = document.getElementById('main-title');
console.log(title);

콘솔에 <h1 id="main-title">오늘의 할 일</h1>처럼 보이면 찾기에 성공한 것입니다.

같은 요소를 querySelector()로도 찾을 수 있습니다.

const sameTitle = document.querySelector('#main-title');
console.log(sameTitle);

여기서 #main-title은 CSS에서 쓰던 선택자와 같습니다. 아이디를 찾을 때는 앞에 #을 붙입니다.

클래스를 찾을 때는 .을 붙입니다.

const message = document.querySelector('.message');
console.log(message);

태그 이름으로도 찾을 수 있습니다.

const firstItem = document.querySelector('li');
console.log(firstItem);

주의할 점이 있습니다. querySelector('li')는 모든 li를 찾는 것이 아니라, 조건에 맞는 첫 번째 요소 하나만 찾습니다. 지금 예제에서는 메일 확인 항목이 선택됩니다.

글자 바꾸기: textContent

요소를 찾았다면 이제 바꿔 보겠습니다. 가장 먼저 바꿀 수 있는 것은 글자입니다.

const title = document.getElementById('main-title');
title.textContent = 'DOM으로 바꾼 제목';

화면의 제목이 바로 바뀝니다. HTML 파일을 직접 수정하지 않았는데도 브라우저 화면이 달라졌습니다. 이것이 DOM 조작입니다.

안내 문구도 바꿔 보겠습니다.

const message = document.querySelector('.message');
message.textContent = '첫 번째 할 일을 확인했습니다.';

textContent는 요소 안의 글자를 다룰 때 사용합니다. 텍스트를 안전하고 단순하게 바꾸고 싶을 때 먼저 떠올리면 됩니다.

예를 들어 아래처럼 입력하면 <strong>이라는 글자가 그대로 보입니다.

message.textContent = '<strong>중요</strong>';

textContent는 HTML 태그로 해석하지 않고, 말 그대로 글자로 넣기 때문입니다.

HTML 넣기: innerHTML

때로는 글자만이 아니라 HTML 태그까지 넣고 싶을 수 있습니다. 이때 innerHTML을 사용할 수 있습니다.

const message = document.querySelector('.message');
message.innerHTML = '<strong>중요:</strong> 오늘 안에 끝내야 합니다.';

이번에는 strong 태그가 적용되어 "중요:" 부분이 굵게 보입니다.

다만 처음에는 innerHTML을 조심해서 쓰는 습관이 좋습니다. 특히 사용자가 입력한 내용을 그대로 innerHTML에 넣으면, 단순한 글자가 아니라 HTML 코드처럼 해석될 수 있습니다. 단순히 글자만 바꿀 때는 textContent를 사용하는 편이 안전합니다.

정리하면 이렇습니다.

// 글자만 바꿀 때
message.textContent = '안내 문구입니다.';

// HTML 태그까지 넣고 싶을 때
message.innerHTML = '<strong>중요한 안내</strong>입니다.';

속성 바꾸기: setAttribute()

HTML 요소에는 속성이 있습니다. 링크의 href, 이미지의 src, 입력칸의 placeholder 같은 것들입니다.

이번 실습 파일에는 이런 링크가 있습니다.

<a rel="nofollow ugc noopener" id="help-link" href="https://developer.mozilla.org/ko/">도움말 보기</a>

링크 주소를 자바스크립트로 바꿔 보겠습니다.

const link = document.getElementById('help-link');
link.setAttribute('href', 'https://developer.mozilla.org/ko/docs/Web/JavaScript');

이제 화면의 도움말 보기 링크를 클릭하면 자바스크립트 문서 쪽으로 이동합니다.

setAttribute()는 "이 속성을 이 값으로 설정해 줘"라는 뜻입니다.

요소.setAttribute('속성이름', '새 값');

링크에 새 창으로 열리게 하는 속성도 붙일 수 있습니다.

link.setAttribute('target', '_blank');

화면에 바로 보이지 않는 속성도 중요합니다. 예를 들어 이미지의 alt 속성은 이미지를 볼 수 없는 상황이나 화면 읽기 도구를 사용하는 상황에서 이미지의 의미를 전달합니다. 화면에 보이는 것만이 웹페이지의 전부는 아닙니다.

스타일 바꾸기: classList

자바스크립트로 직접 색상이나 글자 크기를 바꿀 수도 있습니다.

const title = document.getElementById('main-title');
title.style.color = 'blue';

하지만 실무에서는 자바스크립트가 스타일 하나하나를 직접 정하기보다, CSS에 만들어 둔 클래스를 붙였다 떼는 방식이 더 많이 쓰입니다.

이미 HTML 파일의 style 안에 이런 클래스가 있었습니다.

.highlight {
  background-color: yellow;
  font-weight: bold;
}

이 클래스를 제목에 붙여 보겠습니다.

const title = document.getElementById('main-title');
title.classList.add('highlight');

제목에 노란 배경과 굵은 글씨가 적용됩니다.

다시 제거할 수도 있습니다.

title.classList.remove('highlight');

있으면 빼고, 없으면 붙이는 동작은 toggle()로 할 수 있습니다.

title.classList.toggle('highlight');

이 방식의 장점은 역할이 분명하다는 점입니다. CSS는 "강조하면 어떤 모양인가"를 정하고, 자바스크립트는 "언제 강조할 것인가"를 정합니다.

새 요소 만들기: createElement()와 appendChild()

이제 화면에 없던 항목을 새로 추가해 보겠습니다.

현재 목록은 이렇게 생겼습니다.

<ul id="todo-list">
  <li>메일 확인</li>
  <li>회의 준비</li>
</ul>

여기에 자료 정리라는 새 항목을 추가하겠습니다.

const list = document.getElementById('todo-list');

const newItem = document.createElement('li');
newItem.textContent = '자료 정리';

list.appendChild(newItem);

한 줄씩 보면 어렵지 않습니다.

const list = document.getElementById('todo-list');

새 항목이 들어갈 부모 요소를 찾습니다.

const newItem = document.createElement('li');

아직 화면에는 보이지 않는 새 li 요소를 만듭니다. 종이에 적기 전, 빈 메모지를 한 장 꺼낸 상태와 비슷합니다.

newItem.textContent = '자료 정리';

그 메모지에 글자를 씁니다.

list.appendChild(newItem);

마지막으로 ul 목록의 자식으로 붙입니다. 이때 화면에 새 항목이 나타납니다.

createElement()만으로는 화면에 보이지 않습니다. 만들고, 내용을 채우고, 어딘가에 붙여야 합니다.

요소 삭제하기: remove()

추가할 수 있다면 삭제도 할 수 있습니다.

첫 번째 항목을 찾아 삭제해 보겠습니다.

const firstItem = document.querySelector('li');
firstItem.remove();

화면에서 메일 확인 항목이 사라집니다.

새로 만든 항목도 삭제할 수 있습니다.

const list = document.getElementById('todo-list');
const item = document.createElement('li');
item.textContent = '잠깐 추가한 항목';
list.appendChild(item);

item.remove();

추가했다가 바로 삭제했기 때문에 화면에는 거의 보이지 않을 수 있습니다. 중요한 것은 remove()가 "이 요소를 DOM에서 빼라"는 명령이라는 점입니다.

작은 목록 기능 만들기

이제 지금까지 배운 내용을 묶어 작은 기능처럼 만들어 보겠습니다. 아직 버튼 클릭은 연결하지 않습니다. 클릭에 반응하는 방법은 다음 장에서 다룹니다. 이번에는 콘솔에서 함수를 직접 호출해 화면이 바뀌는지 확인합니다.

콘솔에 아래 코드를 입력해 보세요.

function addTodo(text) {
  const list = document.getElementById('todo-list');

  const item = document.createElement('li');
  item.textContent = text;

  list.appendChild(item);
}

이제 함수를 호출합니다.

addTodo('책상 정리');
addTodo('영수증 확인');

목록에 새 항목이 하나씩 추가됩니다.

이번에는 마지막 항목을 완료 표시해 보겠습니다.

const items = document.querySelectorAll('#todo-list li');
const lastItem = items[items.length - 1];
lastItem.classList.add('done');

여기서 querySelectorAll()은 조건에 맞는 요소 여러 개를 찾습니다. 결과는 배열과 아주 비슷하게 다룰 수 있어서 items[0], items[1]처럼 위치로 접근할 수 있습니다. 마지막 위치는 배열에서 배운 것처럼 length - 1입니다.

다만 정확히 말하면 querySelectorAll()의 결과는 진짜 배열이 아니라 NodeList라는 묶음입니다. 지금처럼 위치로 꺼내고 length를 확인하는 정도는 배열처럼 생각해도 괜찮습니다.

마지막 항목을 삭제하는 함수도 만들 수 있습니다.

function removeLastTodo() {
  const items = document.querySelectorAll('#todo-list li');
  const lastItem = items[items.length - 1];

  if (lastItem) {
    lastItem.remove();
  }
}

호출해 보세요.

removeLastTodo();

if (lastItem)은 삭제할 항목이 있을 때만 remove()를 실행하겠다는 뜻입니다. 목록이 비어 있는데 삭제하려고 하면 오류가 날 수 있으니, 먼저 확인하는 습관이 좋습니다.

자주 만나는 오류 읽기

DOM을 처음 다룰 때 자주 보는 오류가 있습니다.

Cannot set properties of null

이 오류는 보통 "찾은 요소가 없는데, 그 요소를 바꾸려고 했다"는 뜻입니다.

예를 들어 아이디 이름을 잘못 쓰면 이런 일이 생깁니다.

const title = document.getElementById('main-titel');
title.textContent = '새 제목';

HTML에는 main-title이 있는데 코드에는 main-titel이라고 썼습니다. 그러면 title에는 요소가 아니라 null이 들어갑니다. null은 "비어 있음"에 가까운 값이므로 textContent를 바꿀 수 없습니다.

이럴 때는 바로 고치기 전에 먼저 확인해 보세요.

const title = document.getElementById('main-titel');
console.log(title);

콘솔에 null이 나오면 선택자가 틀렸거나, 아직 HTML 요소가 만들어지기 전에 자바스크립트가 실행된 것입니다. 지금처럼 페이지를 연 뒤 콘솔에서 직접 실행할 때는 대부분 선택자 오타가 원인입니다.

또 하나 자주 나오는 실수는 대소문자입니다.

title.classlist.add('highlight');

이 코드는 동작하지 않습니다. 정확한 이름은 classList입니다. 자바스크립트는 대문자와 소문자를 구분합니다.

마지막으로, 앞에서 말한 것처럼 콘솔에서 같은 const 이름을 다시 선언해서 생기는 오류도 있습니다.

Identifier 'title' has already been declared

이 오류가 보이면 DOM을 잘못 다룬 것이 아니라, 같은 이름을 다시 만들려고 했다는 뜻입니다. 페이지를 새로고침하거나 변수 이름을 조금 바꾸면 됩니다.

이 장에서 기억할 것

DOM은 브라우저가 HTML을 읽어 만든 웹페이지 지도입니다. 자바스크립트는 이 지도에서 원하는 요소를 찾고, 글자와 속성과 클래스를 바꿉니다.

요소 하나를 찾을 때는 getElementById()나 querySelector()를 사용할 수 있습니다. 여러 요소를 한 번에 찾을 때는 querySelectorAll()을 사용할 수 있습니다. 글자를 바꿀 때는 textContent, HTML까지 넣을 때는 innerHTML, 속성을 바꿀 때는 setAttribute()를 사용합니다. 스타일은 직접 바꾸기보다 CSS 클래스를 만들어 두고 classList로 붙였다 떼는 방식이 좋습니다.

새 요소는 createElement()로 만들고, appendChild()로 화면에 붙입니다. 필요 없어진 요소는 remove()로 삭제합니다.

이제 자바스크립트가 화면을 바꿀 수 있게 되었습니다. 다음 장에서는 사용자가 버튼을 클릭하거나 입력칸에 글자를 쓰는 순간, 지금 배운 DOM 조작이 자동으로 실행되게 만들어 보겠습니다.

책 목록

비개발자를 위한 JavaScript: 설치 없이 시작해 작은 프로젝트까지

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기