Content categories

김동현·2026년 3월 2일

mdn 학습 번역 - HTML

목록 보기
20/31

콘텐츠 카테고리 (Content categories)

대부분의 HTML 요소(element)들은 하나 이상의 콘텐츠 카테고리(content categories)에 속해 있어요. 이 카테고리들은 공통적인 특성을 공유하는 요소들을 하나의 그룹으로 묶어주는 역할을 한답니다. 비록 아주 엄격한 그룹화는 아니지만(이 카테고리들에 속한다고 해서 요소들 간에 직접적인 관계가 생기는 건 아니에요), 각 카테고리가 공유하는 동작 방식과 관련 규칙들을 정의하고 설명하는 데 큰 도움을 줍니다. 물론 어떤 카테고리에도 속하지 않는 요소들도 존재해요.

이러한 콘텐츠 카테고리들은 요소들의 콘텐츠 모델(content model)을 정의할 때 사용됩니다. 쉽게 말해, 어떤 요소가 자신의 자식(descendants)으로 어떤 요소들을 품을 수 있는지를 결정하는 거죠. 예를 들어, <p> 요소는 오직 프레이징 콘텐츠(phrasing content)만 포함할 수 있는 반면, <div> 요소는 플로우 콘텐츠(flow content)를 포함할 수 있어요. <ins>와 같은 일부 요소들은 아주 독특하게도 투명한(transparent) 콘텐츠 모델을 가지고 있기도 합니다.

콘텐츠 카테고리에는 크게 7가지 주요 카테고리가 있으며, 아래의 벤 다이어그램을 통해 한눈에 요약해 볼 수 있어요.

A Venn diagram showing how the various content categories interrelate. The following sections explain these relationships in text.

참고: > 이 콘텐츠 카테고리들에 대한 더 깊이 있는 논의나 비교 분석은 이 문서의 범위를 벗어납니다. 더 자세한 내용이 궁금하시다면 HTML 스펙의 관련 부분을 직접 읽어보시는 것을 추천해 드려요.

💡 강사의 팁: 프론트엔드 개발자 기술 면접에서 "시맨틱 마크업을 어떻게 하시나요?" 혹은 "인라인 요소와 블록 요소의 차이가 무엇인가요?"라는 질문을 종종 받으실 거예요. 사실 HTML5로 넘어오면서 인라인/블록이라는 시각적인 개념보다는, 문서의 구조를 의미론적으로 정의하는 이 '콘텐츠 카테고리'와 '콘텐츠 모델'이 훨씬 더 중요한 기준이 되었답니다. 면접에서 이런 차이를 정확히 설명하거나, 포트폴리오 프로젝트를 만드실 때 이 규칙에 맞게 마크업을 하시면 기본기가 아주 탄탄하다는 긍정적인 인상을 줄 수 있어요!


메타데이터 콘텐츠 (Metadata content)

메타데이터 콘텐츠 카테고리에 속하는 요소들은 문서 나머지 부분의 표현이나 동작 방식을 수정하거나, 다른 문서와의 링크를 설정하거나, 기타 대역 외(out-of-band) 정보를 전달하는 역할을 합니다. <title>, <link>, <script>, <style>, 그리고 비교적 덜 사용되는 <base>를 포함하여 <head> 태그 안에 들어가는 모든 것들이 바로 메타데이터 콘텐츠예요. 이러한 요소들로 표현할 수 없는 기타 메타데이터를 위해서는 <meta> 요소를 사용한답니다.

메타데이터 요소들은 다음과 같아요:

이 중 일부 요소들은 하나 이상의 콘텐츠 카테고리에 속하기도 해요. 예를 들어, <script>는 메타데이터, 플로우, 프레이징 콘텐츠 카테고리에 모두 속하며, 동시에 스크립트 지원 요소이기도 하죠. 즉, <script>는 메타데이터 콘텐츠, 프레이징 콘텐츠, 또는 스크립트 지원 요소가 들어갈 수 있는 곳이라면 어디든 사용할 수 있다는 뜻이에요.

💡 강사의 팁: 나중에 React나 Next.js 같은 프레임워크를 본격적으로 다루시게 되면, SEO(검색 엔진 최적화)를 위해 <Head> 컴포넌트를 사용하여 이 메타데이터들을 동적으로 주입하는 작업을 정말 많이 하시게 될 거예요. 그때 이 태그들의 역할을 제대로 알고 있으면 훨씬 수월하게 작업할 수 있답니다.


플로우 콘텐츠 (Flow content)

플로우 콘텐츠는 헤딩 요소, 섹셔닝 요소, 프레이징 요소, 임베딩 요소, 인터랙티브 요소, 그리고 폼 관련 요소를 포함하여 <body> 요소 안에 들어갈 수 있는 대부분의 요소들을 아우르는 아주 광범위한 카테고리예요. 텍스트 노드도 여기에 포함되지만, 공백 문자(white space)로만 이루어진 텍스트 노드는 제외됩니다.

플로우 요소들은 다음과 같습니다:

이 외에도 특정한 조건을 만족할 때만 이 카테고리에 속하는 요소들이 몇 가지 있어요:


섹셔닝 콘텐츠 (Sectioning content)

플로우 콘텐츠의 하위 집합인 섹셔닝 콘텐츠는 <header><footer> 요소의 범위를 정의하는 현재 개요(outline) 상의 섹션을 생성해요.

섹셔닝 요소들은 다음과 같습니다:

💡 강사의 팁: 나중에 포트폴리오로 새 프로젝트를 구상 중이시라면, 이 4가지 섹셔닝 태그를 꼭 적극적으로 활용해 보세요. 화면 스크린 리더 등 웹 접근성을 높여주는 핵심 기술이거든요!


헤딩 콘텐츠 (Heading content)

역시 플로우 콘텐츠의 하위 집합인 헤딩 콘텐츠는 특정 섹션의 제목을 정의합니다. 이 정의는 명시적인 섹셔닝 콘텐츠 요소로 표시된 섹션뿐만 아니라, 헤딩 콘텐츠 자체에 의해 암시적으로 정의된 섹션에도 똑같이 적용된답니다.

헤딩 요소들은 다음과 같아요:

참고:
<header> 안에는 헤딩 콘텐츠가 들어갈 확률이 아주 높지만, <header> 요소 그 자체는 헤딩 콘텐츠가 아니라는 점, 꼭 기억해 두세요!


프레이징 콘텐츠 (Phrasing content)

플로우 콘텐츠의 하위 집합인 프레이징 콘텐츠는 문서 내의 '텍스트'와 그 텍스트를 감싸고 있는 '마크업'을 의미해요. 이 프레이징 콘텐츠들이 연속적으로 모여서 하나의 문단(paragraphs)을 구성하게 됩니다.

프레이징 요소들은 다음과 같습니다:

마찬가지로, 특정 조건을 충족할 때만 프레이징 콘텐츠가 되는 요소들도 있어요:

  • <a> : 프레이징 콘텐츠만 포함하고 있을 경우
  • <area> : <map> 요소의 자식인 경우
  • <del> : 프레이징 콘텐츠만 포함하고 있을 경우
  • <ins> : 프레이징 콘텐츠만 포함하고 있을 경우
  • <link> : itemprop 속성이 존재하는 경우
  • <map> : 프레이징 콘텐츠만 포함하고 있을 경우
  • <meta> : itemprop 속성이 존재하는 경우

💡 강사의 팁: 문단을 나타내는 <p> 태그는 오직 이 프레이징 콘텐츠만을 자식으로 받을 수 있어요. 만약 <p> 안에 거대한 <div> 블록을 넣는다면 HTML 명세에 어긋나는 거랍니다. 이런 사소하지만 중요한 규칙들을 지키는 것이 훌륭한 프론트엔드 개발자의 덕목이죠!


임베디드 콘텐츠 (Embedded content)

플로우 콘텐츠의 하위 집합인 임베디드 콘텐츠는 문서에 다른 외부 리소스를 가져오거나, 다른 마크업 언어(SVG, MathML 등) 또는 네임스페이스로 작성된 콘텐츠를 삽입하는 역할을 합니다.

임베디드 콘텐츠 요소들은 다음과 같아요:


인터랙티브 콘텐츠 (Interactive content)

인터랙티브 콘텐츠도 플로우 콘텐츠의 일부로, 사용자와의 상호작용(Interaction)을 위해 특별히 설계된 요소들을 말합니다. 우리가 클릭하고 타이핑하는 요소들이죠!

인터랙티브 콘텐츠 요소들은 다음과 같아요:

특정 조건 하에서만 이 카테고리에 속하는 요소들은 다음과 같습니다:


팰퍼블 콘텐츠 (Palpable content)

팰퍼블(Palpable, 감지할 수 있는/실질적인) 콘텐츠는 내용이 비어있지도, 숨겨져 있지도 않은 실질적으로 화면에 렌더링되는 콘텐츠를 뜻합니다. 팰퍼블 콘텐츠는 어떤 요소의 콘텐츠 모델을 정의할 때 쓰인다기보다는 일반적인 규칙을 정의할 때 사용돼요. 어떤 요소의 콘텐츠 모델이 플로우 콘텐츠나 프레이징 콘텐츠를 허용한다면, 그 요소의 내용물 중에는 hidden 속성이 지정되지 않은 팰퍼블 콘텐츠 노드가 적어도 하나 이상 있어야 한다는 규칙이 있죠.

팰퍼블 요소들은 다음과 같습니다:

특정 조건 하에서만 팰퍼블 콘텐츠가 되는 요소들도 있어요:

  • <audio> : controls 속성이 존재하는 경우
  • <dl> : 자식 요소 중에 이름-값 그룹(name-value group)이 하나라도 포함된 경우
  • <input> : type 속성이 hidden 상태가 아닌 경우
  • <ol> : 자식 요소 중에 <li> 요소가 적어도 하나 포함된 경우
  • <ul> : 자식 요소 중에 <li> 요소가 적어도 하나 포함된 경우

카테고리가 없는 요소들 (Elements without a category)

어떤 콘텐츠 카테고리에도 속하지 않는 요소들도 여러 개 존재한답니다. 목록은 다음과 같아요:

💡 강사의 팁: 카테고리가 없다고 해서 쓸모없는 태그라는 뜻이 전혀 아니에요! 이들은 주로 부모-자식 관계가 명확하게 정해져 있는 표(<table>) 내부 요소나 리스트(<ul>, <ol>) 내부 요소들이기 때문에 특정 콘텐츠 카테고리로 묶어 부를 필요가 없는 것뿐이랍니다.


스크립트 지원 요소 (Script-supporting elements)

스크립트 지원 요소들은 화면에 렌더링되어 우리 눈에 직접 보이는 결과물에는 기여하지 않아요. 대신, 스크립트 코드를 직접 포함하거나 지정하고, 혹은 스크립트에서 사용할 데이터를 명시함으로써 스크립트의 실행을 돕는 역할을 합니다. 특정 자식만 허용하는 요소들(예: <li> 요소만 자식으로 받는 <ul>)을 포함해서 거의 모든 HTML 요소들은 이 스크립트 지원 요소를 자식으로 포함할 수 있어요.

스크립트 지원 요소들은 다음과 같습니다:


폼 연관 콘텐츠 (Form-associated content)

폼 연관 콘텐츠는 플로우 콘텐츠의 하위 집합으로, 명확한 '폼 소유자(form owner)'를 가지고 있으며 플로우 콘텐츠가 올 수 있는 곳이라면 어디든 사용할 수 있는 요소들로 이루어져 있어요. 여기서 폼 소유자란, 해당 요소를 감싸고 있는 <form> 요소이거나, 요소의 form 속성에 id 값으로 연결된 <form>을 말합니다.

폼 연관 요소들은 다음과 같아요:

이 카테고리는 다시 여러 하위 카테고리로 나눌 수 있어요:


투명한 콘텐츠 모델 (Transparent content model)

지금까지 나열된 콘텐츠 카테고리 외에도, 어떤 요소의 콘텐츠 모델은 "투명하다(transparent)"고 정의될 수도 있어요. 정말 중요한 개념이니 집중해 주세요!

어떤 요소 X가 허용하는 콘텐츠가 "투명"하다면, 우리는 그 요소 X의 부모를 살펴봐야 합니다. X의 부모가 허용하는 콘텐츠와 X의 원래 콘텐츠 카테고리 속성을 교집합 한 결과가 바로 여기서 말하는 "투명함"의 의미가 돼요. 만약 X의 부모 역시 투명한 콘텐츠 모델을 가졌다면, 투명하지 않은 콘텐츠 모델을 가진 부모를 찾을 때까지 트리 구조를 타고 위로 올라갑니다. 그렇게 찾아 올라가도 부모가 없다면, 그럴 때 "투명"은 "플로우 콘텐츠(flow content)"를 의미하게 됩니다.

💡 강사의 팁: 간단하게 말하면 "투명한 요소"는 자식 요소 검사를 할 때 자기 자신은 없는 셈 치고 부모의 규칙을 그대로 물려받는 요소예요. 대표적으로 <a> 태그가 그렇죠. <div> 안에 있는 <a> 태그는 또 다른 <div>를 자식으로 가질 수 있지만, <p> 태그 안에 있는 <a> 태그는 오직 텍스트 같은 프레이징 콘텐츠만 자식으로 가질 수 있어요. 프론트엔드 개발하실 때 마크업 구조 오류를 방지하는 아주 핵심적인 지식입니다!

예를 하나 들어볼게요. <ruby> 요소는 프레이징 콘텐츠를 자식으로 허용해요. 그리고 <ins> 요소는 내부에 프레이징 콘텐츠만 포함하고 있을 때 프레이징 콘텐츠 카테고리로 분류됩니다. 따라서 <ins> 요소는 <ruby> 요소 안에 배치될 수 있죠. <ins> 요소가 허용하는 콘텐츠는 "투명"한데, <ruby> 안에 중첩되어 있으므로 이때의 투명함은 "프레이징 콘텐츠"를 의미하게 됩니다. 반면에, <rt> 요소는 프레이징 콘텐츠가 아니에요. 그렇기 때문에 <rt> 요소는 이 <ins> 요소 안에 중첩될 수 없습니다. 비록 <rt><ins> 모두 <ruby> 안에는 들어갈 수 있고 <ins>가 "투명"하더라도 말이에요.

<ruby>
  Text before
  <ins>
    <!-- Invalid: rt cannot be placed inside ins here -->
    <rt>Pronunciation</rt>
  </ins>
</ruby>
<ruby>
  Text before
   <!-- Valid: ins can be inside ruby, and rt can be inside ruby -->
  <ins>Inserted text</ins>
  <rt>Pronunciation</rt>
</ruby>
<ruby>
  Text before
  <!-- Valid: rt can be inside ruby, and ins can be inside rt -->
  <rt><ins>Pronunciation</ins></rt>
</ruby>

1. 카테고리 vs 콘텐츠 모델 (허용되는 자식)

HTML 명세(Spec)를 보면 각 요소는 크게 두 가지 정의를 가집니다.
1. 카테고리: 이 요소가 "어디에" 속하는가? (예: <rt>는 프레이징 콘텐츠 카테고리가 아님)
2. 콘텐츠 모델: 이 요소가 자식으로 "누구를" 허용하는가? (예: <ruby>는 자식으로 누구를 가질 수 있는가?)

2. <rt><ruby> 안에 들어갈 수 있는 이유

<ruby> 요소의 정의를 자세히 보면, 자식으로 오직 '프레이징 콘텐츠'만 허용하는 게 아니라, 특별히 지정된 요소들을 함께 허용하고 있어요.

HTML 표준에 정의된 <ruby>의 콘텐츠 모델은 다음과 같습니다:

  • 프레이징 콘텐츠 (Phrasing content)
  • 그리고 <rt> 요소
  • 그리고 <rp> 요소

즉, <rt>가 프레이징 콘텐츠 카테고리에 속하기 때문이 아니라, <ruby> 요소의 문법 자체가 <rt>를 자신의 직계 자식으로 쓰기로 약속(명시)했기 때문에 배치가 가능한 것입니다. 마치 특정 파티(<ruby>)에 일반 회원(프레이징 콘텐츠)들뿐만 아니라, 특별 초대권을 가진 VIP(<rt>)도 입장할 수 있는 것과 같죠.

3. 왜 <ins> 안에는 <rt>가 못 들어갈까요?

여기가 질문하신 문장의 핵심 포인트입니다! <ins>'투명(Transparent)'한 콘텐츠 모델을 가집니다.

  • 투명함의 의미: <ins>의 부모가 허용하는 자식을 그대로 허용한다는 뜻입니다.
  • <ruby> 안에 <ins>가 있다면, 이때의 <ins>는 부모인 <ruby>가 허용하는 '프레이징 콘텐츠'를 자식으로 가질 수 있습니다.

하지만 여기서 결정적인 차이가 발생합니다! HTML 명세에서 '투명한 요소'는 부모가 허용하는 '카테고리(프레이징 콘텐츠 등)'는 물려받지만, 부모 요소가 가지는 '특수 예외 자식(예: <rt>)까지는 물려받지 못합니다.

따라서 구조를 정리해 보면 이렇습니다:
1. <ruby><rt> : 가능! (루비의 특수 문법으로 허용)
2. <ruby><ins> → 프레이징 콘텐츠 : 가능! (투명한 모델 적용)
3. <ruby><ins><rt> : 불가능! ( <ins>는 프레이징 콘텐츠만 허용하는데, <rt>는 프레이징 콘텐츠가 아니므로 탈락!)

명심하세요. "투명(Transparent)"이라는 것은 콘텐츠 카테고리가 아니라 콘텐츠 모델입니다. 즉, 어떤 요소가 자신의 내부에 무엇을 담을 수 있는지만 정의할 뿐, 요소 자신이 어디에 배치될 수 있는지를 정의하는 것은 아니에요.
바꿔 말하면, 어떤 요소의 자식들이 규칙에 맞게 들어왔는지 판단할 때, 투명한 자식들을 무작정 꿰뚫어 볼 수 없다는 뜻입니다. 예를 들어, <ul> 요소는 오직 <li> 요소와 스크립트 지원 요소만을 자식으로 허용해요. 따라서 그 안에 <del>이나 <ins>가 들어오는 것은 허용되지 않습니다. 비록 그 <del> 태그가 오직 <li> 요소만을 감싸고 있다고 해도 말이죠.

<ul>
  <del>
    <li>Oranges</li>
    <li>Toilet paper</li>
  </del>
  <li>Toothpaste</li>
</ul>
<ul>
  <li><del>Oranges</del></li>
  <li><del>Toilet paper</del></li>
  <li>Toothpaste</li>
</ul>
profile
프론트에_가까운_풀스택_개발자

0개의 댓글