반갑습니다! 시니어 프론트엔드 개발자로서 MDN 문서를 공부하시는 것을 도와드릴게요. 말씀하신 대로 공식 문서의 내용들을 하나도 빠짐없이, 하지만 딱딱하지 않은 편안한 구어체로 전부 번역해 드립니다.
문서에 포함된 이미지와 링크들도 잘 동작하도록 Markdown으로 구성했어요. 자, 그럼 시작해 볼까요?
이 글에서는 HTML 요소와 상호작용하는 HTML DOM의 부분들에 집중해 볼게요. 드래그 앤 드롭(Drag and Drop), 웹소켓(WebSockets), 웹 스토리지(Web Storage) 같은 다른 영역에 대한 내용은 해당 API 문서에서 찾아보실 수 있어요.
문서 객체 모델(DOM)은 document의](https://developer.mozilla.org/en-US/docs/Web/API/Document)의) 구조를 설명하는 아키텍처예요. 각 문서는 Document 인터페이스의 인스턴스로 표현된답니다. 문서는 다시 노드(nodes) 들의 계층적인 트리로 구성되는데, 여기서 노드란 문서 내의 단일 객체(요소나 텍스트 노드 등)를 나타내는 가장 기본적인 레코드에요.
노드는 단순히 다른 노드들을 그룹화하거나 계층 구조를 만들 수 있는 지점을 제공하는 등 엄격하게 조직적인 역할을 할 수도 있고, 혹은 문서의 시각적인 구성 요소를 나타낼 수도 있어요. 각 노드는 Node 인터페이스를 기반으로 하는데요, 이 인터페이스는 노드에 대한 정보를 가져오는 속성뿐만 아니라 DOM 내에서 노드를 생성하고, 삭제하며, 구성하기 위한 메서드들을 제공해 줍니다.
사실 노드 자체에는 문서에 실제로 표시되는 콘텐츠를 포함한다는 개념이 없어요. 그냥 빈 그릇과 같죠. 시각적인 콘텐츠를 표현할 수 있는 노드라는 기본적인 개념은 Element 인터페이스에서 도입되었어요. Element 객체 인스턴스는 HTML이나 SVG 같은 XML 어휘를 사용해 생성된 문서 내의 단일 요소를 나타낸답니다.
예를 들어, 두 개의 요소가 있고 그중 하나 안에 또 다른 두 개의 요소가 중첩되어 있는 문서를 생각해 볼게요.
Document 인터페이스는 DOM 명세의 일부로 정의되어 있지만, HTML 명세는 웹 브라우저 환경에서 DOM을 사용하거나 특별히 HTML 문서를 나타내는 데 필요한 정보들을 추가하여 이를 크게 확장했어요.
HTML 표준에 의해 Document에 추가된 것들은 다음과 같아요:
<head> 블록과 본문(body)에 있는 요소 목록은 물론, 문서에 포함된 이미지(images), 링크(links), 스크립트(scripts) 등의 목록에도 접근할 수 있어요.copy, cut, paste 동작만 포함되어 있답니다.Element 인터페이스는 특정 HTML 요소들을 표현하기 위해 HTMLElement 인터페이스를 도입하면서 한 단계 더 구체화되었어요. 모든 하위 HTML 요소 클래스들은 이 인터페이스를 상속받게 되죠. 이를 통해 Element 클래스가 확장되어 요소 노드에 HTML 고유의 일반적인 기능들이 추가되었어요. HTMLElement가 추가한 속성으로는 예를 들어 hidden과](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/hidden)과) innerText가](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText)가) 있답니다.
HTML 문서는 각각의 노드가 HTML 요소인 DOM 트리이고, 이 요소들은 HTMLElement 인터페이스로 표현돼요. 그리고 HTMLElement 클래스는 다시 Node를 구현하기 때문에, 모든 요소는 곧 노드이기도 해요 (하지만 노드라고 해서 항상 요소인 것은 아니에요). 이런 방식으로 Node 인터페이스가 구현하는 구조적인 기능들을 HTML 요소에서도 사용할 수 있어서, 요소끼리 서로 중첩되거나, 생성하고 삭제하며, 이리저리 이동시키는 것 등이 가능해지는 거예요.
하지만 HTMLElement 인터페이스는 범용적이라서 요소의 ID, 좌표, 요소를 구성하는 HTML 마크업, 스크롤 위치 정보 등 모든 HTML 요소가 공유하는 공통적인 기능만 제공해요.
따라서 특정 요소에 필요한 기능을 제공하기 위해 핵심 HTMLElement 인터페이스의 기능을 확장하려면, HTMLElement 클래스를 상속받는 하위 클래스(subclass)를 만들어 필요한 속성과 메서드를 추가해야 해요. 예를 들어 <canvas> 요소는 HTMLCanvasElement 타입의 객체로 표현되는데요. HTMLCanvasElement는 캔버스 전용 기능을 제공하기 위해 height 같은 속성이나 getContext() 같은 메서드를 추가하여 HTMLElement 타입을 보강한 것이죠.
HTML 요소 클래스들의 전반적인 상속 구조는 다음과 같이 생겼어요:
이처럼 요소는 모든 조상 인터페이스의 속성과 메서드를 상속받아요. 예를 들어 DOM에서 HTMLAnchorElement 타입의 객체로 표현되는 <a> 요소를 생각해 볼까요? 이 요소는 해당 클래스의 문서에 설명된 앵커 전용 속성과 메서드를 포함할 뿐만 아니라, HTMLElement와](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)와) Element, 나아가 Node 그리고 마지막으로 EventTarget에](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)에) 정의된 것들까지 모두 포함하고 있답니다.
각 레벨은 요소가 가지는 유용성의 핵심적인 측면을 정의하고 있어요. Node로부터는 요소가 다른 요소에 포함되거나 직접 다른 요소를 포함할 수 있는 능력과 관련된 개념을 상속받죠. 특히 중요한 것은 EventTarget으로부터 얻게 되는 것인데요, 바로 마우스 클릭이나 미디어의 재생/일시정지 같은 이벤트를 수신하고 처리할 수 있는 능력이에요.
공통점을 공유해서 추가적인 중간 타입을 가지는 요소들도 있어요. 예를 들어 <audio>와](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/audio)와) <video> 요소는 모두 시청각 미디어를 제공하잖아요? 이에 대응하는 타입인 HTMLAudioElement와](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement)와) HTMLVideoElement는](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement)는) 둘 다 공통 타입인 HTMLMediaElement를](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement)를) 기반으로 하고, 이는 다시 HTMLElement를](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)를) 기반으로 이어지는 구조랍니다. HTMLMediaElement는 오디오와 비디오 요소가 공통으로 가지는 메서드와 속성을 정의해요.
이런 요소별 인터페이스들이 HTML DOM API의 대부분을 차지하고 있으며, 이 문서에서도 가장 핵심적으로 다루는 내용이에요. DOM과 그 전반적인 개념에 대한 소개는 DOM 문서를 참고해 주세요.
HTML DOM이 제공하는 기능들은 웹 개발자의 도구 상자에서 가장 많이 사용되는 API 중 하나예요. 아주 단순한 구조를 제외한 사실상 거의 모든 웹 애플리케이션이 HTML DOM의 기능들을 어느 정도 사용하게 될 거랍니다.
HTML DOM API를 구성하는 인터페이스들의 대부분은 개별 HTML 요소나 비슷한 기능을 가진 소규모 요소 그룹과 거의 일대일로 매핑돼요. 그 외에도 HTML DOM API는 이런 HTML 요소 인터페이스들을 보조하기 위한 몇 가지 인터페이스와 타입들을 포함하고 있어요.
이 인터페이스들은 특정 HTML 요소(또는 동일한 속성과 메서드가 연관된 관련 요소들의 집합)를 나타내요.
HTMLAnchorElementHTMLAreaElementHTMLAudioElementHTMLBaseElementHTMLBodyElementHTMLBRElementHTMLButtonElementHTMLCanvasElementHTMLDataElementHTMLDataListElementHTMLDetailsElementHTMLDialogElementHTMLDirectoryElementHTMLDivElementHTMLDListElementHTMLElementHTMLEmbedElementHTMLFieldSetElementHTMLFormElementHTMLHRElementHTMLHeadElementHTMLHeadingElementHTMLHtmlElementHTMLIFrameElementHTMLImageElementHTMLInputElementHTMLLabelElementHTMLLegendElementHTMLLIElementHTMLLinkElementHTMLMapElementHTMLMediaElementHTMLMenuElementHTMLMetaElementHTMLMeterElementHTMLModElementHTMLObjectElementHTMLOListElementHTMLOptGroupElementHTMLOptionElementHTMLOutputElementHTMLParagraphElementHTMLPictureElementHTMLPreElementHTMLProgressElementHTMLQuoteElementHTMLScriptElementHTMLSelectElementHTMLSlotElementHTMLSourceElementHTMLSpanElementHTMLStyleElementHTMLTableCaptionElementHTMLTableCellElementHTMLTableColElementHTMLTableElementHTMLTableRowElementHTMLTableSectionElementHTMLTemplateElementHTMLTextAreaElementHTMLTimeElementHTMLTitleElementHTMLTrackElementHTMLUListElementHTMLUnknownElementHTMLVideoElementHTMLMarqueeElement (Deprecated)HTMLFontElement (Deprecated)HTMLFrameElement (Deprecated)HTMLFrameSetElement (Deprecated)이 인터페이스들은 HTML을 포함하고 있는 브라우저 창과 문서, 그리고 브라우저의 상태, 사용 가능한 플러그인(있는 경우) 및 다양한 설정 옵션들에 접근할 수 있게 해줘요.
External (Deprecated)Plugin (Deprecated)PluginArray (Deprecated)이 인터페이스들은 <form>과](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form)과) <input> 요소를 포함하여, 폼을 만들고 관리하는 데 사용되는 요소들이 필요로 하는 구조와 기능을 제공해 줍니다.
이 인터페이스들은 캔버스(Canvas) API뿐만 아니라 <img> 요소와 <picture> 요소에서 사용되는 객체들을 나타내요.
CanvasGradientCanvasPatternCanvasRenderingContext2DImageBitmapImageBitmapRenderingContextImageDataOffscreenCanvasOffscreenCanvasRenderingContext2DPath2DTextMetrics미디어 인터페이스들은 미디어 요소인 <audio>와](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/audio)와) <video>의](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/video)의) 콘텐츠에 HTML이 접근할 수 있도록 해줘요.
AudioTrackAudioTrackListMediaErrorTextTrackTextTrackCueTextTrackCueListTextTrackListTimeRangesTrackEventVideoTrackVideoTrackList이 인터페이스들은 HTML 드래그 앤 드롭 API에서 드래그 가능하거나 이미 드래그된 개별 항목들, 이런 항목들의 그룹을 나타내고 드래그 앤 드롭 과정을 처리하는 데 사용된답니다.
히스토리(History) API 인터페이스를 사용하면 브라우저의 방문 기록 정보에 접근할 수 있을 뿐만 아니라, 브라우저의 현재 탭을 그 기록을 따라 앞이나 뒤로 이동시킬 수도 있어요.
BeforeUnloadEventHashChangeEventHistoryLocationPageRevealEventPageSwapEventPageTransitionEventPopStateEvent이 인터페이스들은 웹 컴포넌트 API에서 사용 가능한 사용자 정의 요소(custom elements)를 생성하고 관리하는 데 사용돼요.
이런 지원 목적의 객체 타입들은 HTML DOM API의 다양한 곳에서 여러 방식으로 사용되고 있어요. 추가로, PromiseRejectionEvent는](https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent)는) 자바스크립트(JavaScript)의 Promise가](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)가) 거부(rejected)되었을 때 발생하여 전달되는 이벤트를 나타낸답니다.
DOMStringListDOMStringMapErrorEventHTMLAllCollectionMimeTypeMimeTypeArrayPromiseRejectionEvent일부 인터페이스들은 기술적으로는 HTML 명세에 정의되어 있지만, 실제로는 다른 API에 속해 있어요.
웹 스토리지 API는 웹사이트가 나중에 다시 사용할 수 있도록 사용자 기기에 데이터를 임시로 혹은 영구적으로 저장할 수 있는 기능을 제공해요.
이 인터페이스들은 웹 워커 API에서 워커가 앱 및 해당 콘텐츠와 상호작용할 수 있는 기능을 설정하는 것은 물론, 창이나 앱 간의 메시징을 지원하는 데에도 사용된답니다.
BroadcastChannelDedicatedWorkerGlobalScopeMessageChannelMessageEventMessagePortSharedWorkerSharedWorkerGlobalScopeWorkerWorkerGlobalScopeWorkerLocationWorkerNavigatorHTML 명세에 정의된 이 인터페이스들은 웹소켓 API에서 사용돼요.
EventSource 인터페이스는 서버 전송 이벤트(server-sent events)를 보냈거나 현재 보내고 있는 출처(source)를 나타내요.
이 예제에서는 주어진 입력 필드에 현재 값이 있는지 없는지에 따라 폼의 "제출(submit)" 버튼 상태를 업데이트하기 위해, <input> 요소의 input 이벤트를 모니터링해 볼 거예요.
const nameField = document.getElementById("userName");
const sendButton = document.getElementById("sendButton");
sendButton.disabled = true;
// [참고: 이 문서가 로드될 때마다 항상 이 예제에 포커스가 맞춰져 스크롤이 이동하는 것을 막기 위해 비활성화 해두었습니다]
// nameField.focus();
nameField.addEventListener("input", (event) => {
const elem = event.target;
const valid = elem.value.length !== 0;
if (valid && sendButton.disabled) {
sendButton.disabled = false;
} else if (!valid && !sendButton.disabled) {
sendButton.disabled = true;
}
});
이 코드는 Document 인터페이스의 getElementById() 메서드를 사용해서 ID가 userName과 sendButton인 <input> 요소들을 나타내는 DOM 객체를 가져오고 있어요. 이렇게 가져온 객체들을 통해 우리는 해당 요소에 대한 정보를 얻고 제어할 수 있는 속성들과 메서드들에 접근할 수 있게 됩니다.
"Send" 버튼을 나타내는 HTMLInputElement 객체의 disabled 속성을 true로 설정하면 버튼이 비활성화되어서 클릭할 수 없게 돼요. 그리고 사용자 이름 입력 필드는 HTMLElement로부터](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)로부터) 상속받은 focus() 메서드를 호출하여 활성 포커스 상태로 만들었어요.
그런 다음 addEventListener()를](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)를) 호출해서 사용자 이름 입력란에 input 이벤트를 위한 핸들러를 추가했어요. 이 코드는 입력된 현재 값의 길이를 확인하는데요, 만약 길이가 0이라면 (만약 버튼이 아직 비활성화 상태가 아닐 때) "Send" 버튼을 비활성화시켜요. 반대의 경우라면 버튼이 활성화되도록 보장해 준답니다.
이렇게 설정해두면, 사용자 이름 입력 필드에 값이 있을 때는 항상 "Send" 버튼이 활성화되고, 입력 필드가 비어있을 때는 비활성화되는 모습을 볼 수 있어요.
폼에 사용된 HTML은 다음과 같이 생겼어요:
<p>Please provide the information below. Items marked with "*" are required.</p>
<form action="" method="get">
<p>
<label for="userName" required>Your name:</label>
<input type="text" id="userName" /> (*)
</p>
<p>
<label for="userEmail">Email:</label>
<input type="email" id="userEmail" />
</p>
<input type="submit" value="Send" id="sendButton" />
</form>
(MDN 문서의 이 영역에서는 위의 코드들이 실제로 실행되는 대화형 예제 화면이 렌더링 됩니다.)