문서 읽는 데 66분 · A2

A-2: 텍스트와 링크

전체 23강 중 2강 · HTML·CSS·JS
난이도 · 입문

안녕하세요, 홍순구 튜터입니다. 두 번째 시간이에요!

지난 시간에 우리는 인스타그램 로그인 페이지의 뼈대를 세웠어요. <header>, <main>, <footer> 같은 시멘틱 태그로 영역을 나눠봤죠. 그런데 화면에 띄워보면 뭔가 허전했을 거예요. 텍스트만 덩그러니 있고, 페이지끼리 이동할 수도 없고요.

오늘은 그 뼈대에 을 붙입니다. 제목을 크게 키우고, 문단을 정돈하고, 페이지와 페이지를 링크로 이어볼 거예요. 수업이 끝날 무렵에는 메뉴를 클릭하면 진짜로 다른 페이지로 이동하는 인스타그램이 손에 들어옵니다.

💡 오늘 수업의 핵심 — "제목·문단·강조·목록·링크 다섯 도구로 페이지에 의미를 더하고, 메뉴를 클릭하면 진짜 페이지가 이동한다" 🎯

🎯 학습 목표

  • 제목 태그(<h1>~<h6>)의 위계를 이해하고, 시각 크기와 의미 위계를 구분합니다.
  • 문단(<p>), 줄바꿈(<br>), 수평선(<hr>)의 용도를 구분해서 사용합니다.
  • 시멘틱 강조(<strong>, <em>, <mark>)와 시각 전용(<b>, <i>)의 차이를 압니다.
  • 비순서 목록(<ul>), 순서 목록(<ol>)으로 항목을 정리합니다.
  • <a> 태그로 페이지를 연결하고, 절대 경로상대 경로를 구분합니다.
  • <nav> + <ul> + <a> 조합으로 인스타그램 네비게이션 메뉴를 완성합니다.

Step 1: "제목 태그의 위계 — <h1>부터 <h6>까지"

지난 시간 막바지에 약속드렸죠? "<h1>은 다음 시간에 자세히 배워봅시다" 라고요. 그 약속을 지킬 시간입니다.

제목은 6단계까지 있어요

HTML의 제목 태그는 무려 6단계가 있습니다.

<h1>가장 중요한 제목</h1>
<h2>그 다음으로 중요한 제목</h2>
<h3>세 번째 단계 제목</h3>
<h4>네 번째 단계 제목</h4>
<h5>다섯 번째 단계 제목</h5>
<h6>가장 작은 제목</h6>

hHeading(머리말)의 약자예요. 숫자가 작을수록 더 중요한 제목입니다. 브라우저는 기본적으로 <h1>을 가장 크게, <h6>을 가장 작게 그려줘요.

신문 기사를 떠올려보세요

제목 위계는 신문을 생각하면 쉬워요.

단계 신문에서 웹페이지에서
<h1> 신문 제호 "조선일보", "한겨레" 사이트/페이지 제목 — "Instagram"
<h2> 1면 대제목 — "오늘의 주요 뉴스" 페이지의 큰 섹션 제목
<h3> 기사 제목 섹션 안의 소제목
<h4>~<h6> 기사 안의 소단원, 표 제목 더 깊이 들어갈수록

신문에서 작은 기사의 소제목이 1면 대제목보다 크면 어색하죠? 웹페이지도 마찬가지예요. 위계를 거꾸로 쓰면 읽는 사람이 혼란스러워집니다.

⚠️ 한 페이지에 <h1>은 하나가 원칙

한 페이지에는 <h1>하나만 있는 게 원칙이에요. 그 페이지에서 가장 중요한 제목 딱 한 줄. 책으로 치면 표지의 책 제목 같은 거예요.

🙋 "근데 큰 글씨로 강조하고 싶은데, <h1>을 여러 번 쓰면 안 되나요?" — 안 됩니다. 큰 글씨가 필요하면 CSS로 크기를 키우는 게 정답이에요. 의미와 모양은 분리해야 합니다.

이 원칙을 지키지 않으면 두 가지가 망가져요.

  1. 검색엔진이 페이지 주제를 파악하기 어려워집니다. 구글은 <h1>을 "이 페이지의 주제"로 인식해요.
  2. 스크린 리더가 위계를 안내할 때 혼란스러워집니다. "제목 1: Instagram, 제목 1: 환영합니다, 제목 1: 가입하기..." 같은 식이 되면 사용자가 페이지 구조를 못 파악해요.

인스타그램 로그인 페이지에 위계 적용하기

지난 시간 우리 index.html에는 <h1>Instagram</h1> 하나만 있었어요. 오늘은 그 아래에 <h2>로 환영 메시지를 추가해봅시다.

<!-- instagram-clone-frontend/index.html -->
<header>
  <h1>Instagram</h1>
</header>

<main>
  <section>
    <h2>친구들의 일상에 오신 것을 환영합니다</h2>
    <p>로그인하고 친구들의 사진과 동영상을 확인하세요.</p>
  </section>
</main>

저장하고 브라우저를 확인해보세요. "Instagram"은 큼직하게, "친구들의 일상에 오신 것을 환영합니다"는 그보다 살짝 작게 보일 거예요.

💡 직접 바꿔보세요! <h2><h3>, <h4>로 바꿔가며 저장해보세요. 글씨가 점점 작아지는 게 보일 거예요. 그 다음 다시 <h2>로 돌려놓읍시다.

위계는 건너뛰지 않는 게 좋아요

<h1> 다음에 곧장 <h4>로 점프하는 건 권장되지 않아요. "<h1><h2><h3>" 순서로 차근차근 내려가야 합니다.

🙋 "그럼 <h6>은 언제 써요? 거의 안 보이던데요." — 사실 <h6>은 거의 안 씁니다. 대부분의 페이지는 <h1> ~ <h3> 정도면 충분해요. <h4> 이하는 매우 긴 문서(예: 위키피디아 같은 백과사전)에서나 쓰입니다.

🙋 학생 질문 — "큰 글씨가 필요할 때마다 h1을 쓰면 안 된다면, 어떻게 글씨 크기를 조절해요?"

좋은 질문입니다! CSS로 조절합니다. 다음 모듈(B-1)에서 본격적으로 배울 거예요.

미리 살짝 보여드리면 이런 식입니다.

h2 {
  font-size: 24px;
  color: #333;
}

이렇게 하면 <h2> 태그 모두에 글자 크기와 색상을 적용할 수 있어요. "태그는 의미를 정하고, CSS가 모양을 정한다" — 이 분리가 웹 개발의 가장 중요한 원칙 중 하나예요.


Step 2: "문단을 다루는 세 도구 — <p>, <br>, <hr>"

이번엔 문단을 다뤄봅시다. 지난 시간에 <p> 태그를 살짝 맛만 봤죠? 오늘 정식으로 인사합니다.

<p> — 문단을 감싸는 태그

<p>Paragraph(문단)의 약자예요. 일반 텍스트는 거의 다 <p>로 감쌉니다.

<p>친구들의 일상을 공유하는 공간, Instagram에 오신 것을 환영합니다.</p>
<p>사진과 동영상으로 일상을 기록하고, 친구들과 소통하세요.</p>

<p> 사이에는 자연스럽게 여백이 생겨요. 브라우저가 "문단이 바뀌었구나"를 알고 띄워주는 거예요.

🤔 그런데 이상한 점

<p> 안에서 키보드 엔터를 쳐서 줄바꿈을 시도해보세요.

<p>
  첫 번째 줄입니다.
  두 번째 줄로 가고 싶어요.
  세 번째 줄까지 만들고 싶어요.
</p>

저장하고 브라우저에서 확인하면 — 어라? 한 줄로 죽 이어져서 나옵니다.

HTML은 공백과 줄바꿈을 무시해요. 코드를 보기 좋게 정렬하라고 만든 공백이지, 화면에 그대로 반영되는 건 아니거든요. "코드 가독성"과 "화면 출력"은 별개입니다.

<br> — 줄을 강제로 바꾸는 빈 요소

줄바꿈이 정말 필요한 자리에는 <br> 태그를 씁니다. Break(자르다)의 약자예요.

<p>
  로그인하고 친구들의 사진과 동영상을 확인하세요.<br>
  처음이신가요? 가입은 30초면 충분합니다.
</p>

이렇게 하면 "확인하세요." 다음에 줄이 바뀌어요.

💡 잠깐, <br>은 닫는 태그가 없네요?

여기서 새로운 개념이 등장합니다. 빈 요소(Empty Element) — 닫는 태그가 없는 태그예요.

지금까지 우리가 본 태그들은 "여는 태그 → 내용 → 닫는 태그" 세 부분이 한 세트였죠.

<p>내용</p>
<h1>내용</h1>

그런데 <br>은 "줄을 바꿔라"는 명령만 있을 뿐, 안에 담을 내용이 없어요. 그래서 닫는 태그가 필요 없습니다.

<br>      <!-- OK -->
<br/>     <!-- 옛 스타일 (XHTML), 지금도 유효 -->

빈 요소는 몇 가지 더 있어요. 앞으로 자주 만날 친구들이에요.

태그 역할 등장 시점
<br> 줄바꿈 지금
<hr> 수평선 (잠시 후!) 지금
<img> 이미지 다음 시간(A-3)
<input> 입력칸 A-4 모듈
<meta> 메타 정보 이미 봤어요 (head 안에)

⚠️ <br> 남용 주의

"문단 사이 띄울 때도 <br> 두 번 쓰면 되지 않나요?" 라고 생각할 수 있어요. 가능은 합니다. 하지만 권장되지 않습니다.

<!-- 이렇게 하면 안 돼요 -->
첫 번째 이야기.<br><br>
두 번째 이야기.<br><br>
세 번째 이야기.

<!-- 이렇게 해야 해요 -->
<p>첫 번째 이야기.</p>
<p>두 번째 이야기.</p>
<p>세 번째 이야기.</p>

<br>은 "같은 문단 안에서 줄만 바꿔"라는 뜻이에요. 시 가사 같은 자리에 어울려요.

반면 "여기서 문단이 바뀐다"는 의미는 <p>로 표현합니다. 스크린 리더도 "문단이 끝났습니다, 새 문단이 시작됩니다"를 인식해서 톤을 조정해줘요.

<hr> — 주제 전환 수평선

<hr>Horizontal Rule(수평선)의 약자예요. 페이지를 가로지르는 가로선을 그려줍니다.

<section>
  <p>로그인하고 친구들의 사진과 동영상을 확인하세요.</p>
</section>

<hr>

<section>
  <p>계정이 없으신가요? 가입하기</p>
</section>

저장하고 확인하면 두 영역 사이에 가로선이 그어져요.

🙋 "단순히 모양 때문에 쓰는 건가요?" — 아니에요. <hr>은 "여기서 주제가 전환됩니다"라는 의미를 담는 시멘틱 태그입니다. 모양은 부수적이에요. 스크린 리더도 <hr>을 만나면 "구분선"이라고 안내해줍니다.

💡 직접 실험해보세요! <hr>을 빼면 두 영역 사이 가로선이 사라집니다. 다시 넣으면 돌아와요. 이 가로선의 두께·색깔은 다음 모듈(B-1)에서 CSS로 직접 꾸며볼 거예요.

🙋 학생 질문 — "br 태그 끝에 슬래시(
)를 붙이는 코드도 봤어요. 뭐가 맞는 거예요?"

둘 다 맞습니다. 둘 다 브라우저에서 동일하게 동작해요.

  • <br> — HTML5 표준 스타일
  • <br/> — XHTML(옛 표준) 스타일. 지금도 유효합니다.

옛날에는 XML 규칙을 따르려고 <br/> 형식을 강제했어요. 지금 HTML5는 둘 다 허용합니다. 본 강의에서는 더 간결한 <br>을 씁니다.


Step 3: "텍스트에 의미 있는 강조를 — <strong>, <em>, <mark>"

본문에서 "이 부분이 진짜 중요해요!"라고 말하고 싶을 때가 있죠. 이런 강조에도 HTML 태그가 있습니다. 그것도 의미를 담은 태그로요.

<strong> — 중요한 정보

<strong>은 "강하게 중요한 정보"를 표시할 때 씁니다. 브라우저는 기본적으로 굵게 그려줘요.

<p>비밀번호는 <strong>최소 8자 이상</strong>이어야 합니다.</p>

스크린 리더는 <strong> 부분을 만나면 톤을 살짝 바꿔서 강조해서 읽어줘요. 시각 장애인 사용자도 "아, 여기가 중요한 부분이구나"를 알 수 있는 거예요.

<em> — 강조 (Emphasis)

<em>Emphasis(강조)의 약자예요. 기본적으로 기울임(이탤릭)으로 그려집니다.

<p>가입은 <em>지금 바로</em> 시작할 수 있어요.</p>

🙋 "<strong>이랑 뭐가 다른가요? 둘 다 강조 아닌가요?" — 미묘하지만 다릅니다.

태그 의미 비유
<strong> 중요도가 높다 신문에서 "사망", "긴급" 같은 핵심 단어
<em> 말의 강세 (어조) 대화에서 "지금" 이라고 살짝 힘줘 발음하는 느낌

"비밀번호 8자 이상"은 중요한 정보 → <strong>. "지금 바로 가입"은 어조를 살리는 강조 → <em>.

실무에서는 둘을 엄밀히 구분하지 않고 쓰는 경우도 많아요. 다만 의미가 다르다는 사실은 알아두세요.

<mark> — 형광펜으로 칠한 듯한 강조

<mark>는 "형광펜으로 칠한 부분" 느낌의 강조예요. 노란 배경이 깔립니다.

<p>가입은 <mark>30초</mark>면 충분합니다.</p>

검색 결과 페이지에서 검색어가 노랗게 강조되는 자리, 혹은 "이 부분 봐주세요!" 하고 시선을 끌고 싶은 자리에 어울려요.

⚠️ <b><i> — 보긴 했는데, 권장하지 않아요

옛날 HTML에는 비슷한 태그가 또 있었어요.

태그 의미 모양
<b> Bold 굵게
<i> Italic 기울임

<b><strong>이랑, <i><em>이랑 결과가 똑같이 보여요. 그런데 뭐가 다를까요?

  • <b>, <i>모양만 정합니다. 의미가 없어요.
  • <strong>, <em>의미를 담습니다. 모양은 브라우저가 알아서 정합니다.

🙋 "눈에 보이는 결과가 같으면 뭘 써도 되지 않나요?" — 결과가 같아 보여도 스크린 리더와 검색엔진에게는 다르게 들립니다.

  • <b> → "굵은 글씨예요" (그냥 시각 정보)
  • <strong> → "이건 중요한 정보예요" (의미 정보)

오늘 우리가 배우는 시멘틱 태그의 핵심이 바로 이거예요. "같아 보여도, 다른 뜻" — HTML은 의미를 담는 언어입니다.

본 강의에서는 일관되게 <strong>, <em>을 사용합니다. <b>, <i>는 "읽을 수는 있지만 쓰지는 않는 단어" 정도로 알아두세요.

인스타그램 안내 문구에 강조 적용해보기

index.html의 안내 문구를 강조 태그로 꾸며봅시다.

<!-- instagram-clone-frontend/index.html -->
<main>
  <section>
    <h2>친구들의 일상에 오신 것을 환영합니다</h2>
    <p>
      로그인하고 <strong>실시간</strong>으로
      친구들의 사진과 동영상을 확인하세요.
    </p>
  </section>

  <hr>

  <section>
    <p>계정이 없으신가요? <strong>가입하기</strong></p>
    <p>가입은 <mark>30초</mark>면 충분합니다. <em>지금 바로</em> 시작해보세요.</p>
  </section>
</main>

저장하고 브라우저에서 확인하면 — "실시간"은 굵게, "30초"는 노란 형광펜, "지금 바로"는 기울임으로 보일 거예요.

💡 직접 실험해보세요! <strong><b>로 바꿔보세요. 결과가 똑같죠? 그래도 우리는 <strong>을 씁니다. 이유는 위에서 말씀드린 그대로예요.

🙋 학생 질문 — "굵게 표시되는 게 마음에 안 들어요. 색깔만 빨갛게 강조하고 싶어요."

좋아요, 이게 바로 "태그는 의미, CSS는 모양" 원칙이 빛나는 자리예요.

다음 모듈(B-1)에서 CSS로 이렇게 할 수 있습니다.

strong {
  font-weight: normal;   /* 굵기 제거 */
  color: red;            /* 빨간색 적용 */
}

태그는 그대로 <strong>을 쓰고("이건 중요한 정보야"라는 의미는 유지), 모양만 CSS로 바꾸는 거예요. 의미는 유지, 모양은 자유 — 이게 HTML+CSS 분리의 매력입니다.


Step 4: "목록을 만드는 두 방법 — <ul><ol>"

웹페이지에는 목록이 정말 많이 등장합니다. 메뉴, 할 일, 댓글, 검색 결과 — 다 목록이에요. HTML에는 목록을 위한 전용 태그가 있어요.

두 종류의 목록

목록은 크게 두 가지로 나뉩니다.

태그 풀네임 의미 표시
<ul> Unordered List 순서 없는 목록 점(•)
<ol> Ordered List 순서 있는 목록 숫자 (1, 2, 3)

그 안의 각 항목은 <li>(List Item)로 감쌉니다.

<ul> — 점으로 표시되는 목록

순서가 중요하지 않은 항목을 나열할 때 씁니다.

<ul>
  <li>사진 공유</li>
  <li>스토리 올리기</li>
  <li>친구와 메시지</li>
  <li>릴스(짧은 영상)</li>
</ul>

브라우저에서 보면 각 항목 앞에 까만 점(•)이 붙어요.

🙋 "왜 사진 공유가 먼저고 릴스가 마지막인가요? 순서를 바꿔도 되나요?" — 네, 바꿔도 됩니다. 순서가 의미를 만들지 않으니까요. 그래서 "순서 없는 목록(Unordered)"이라고 부르는 거예요.

<ol> — 숫자로 표시되는 목록

순서가 중요한 항목을 나열할 때 씁니다.

<ol>
  <li>이메일을 입력합니다.</li>
  <li>비밀번호를 설정합니다.</li>
  <li>프로필 사진을 업로드합니다.</li>
  <li>가입 완료!</li>
</ol>

브라우저에서는 자동으로 "1. 2. 3. 4." 가 붙어요. 순서를 바꾸면 의미가 망가집니다 — 비밀번호 설정 전에 가입 완료가 될 수는 없잖아요?

💡 숫자가 자동으로 매겨진다는 게 포인트예요. 중간에 항목을 추가하거나 삭제해도, 브라우저가 알아서 번호를 다시 매겨줘요. 직접 "1. 2. 3." 을 타이핑하는 것보다 훨씬 편합니다.

중첩 목록 — 목록 안의 목록

목록 안에 또 목록을 넣을 수도 있어요. "인스타그램에서 할 수 있는 일 → 그 중 사진 공유 → 그 안의 세부 기능" 같은 계층 구조 자리에 어울려요.

<ul>
  <li>사진 공유
    <ul>
      <li>필터 적용</li>
      <li>위치 태그</li>
      <li>친구 태그</li>
    </ul>
  </li>
  <li>스토리</li>
  <li>릴스</li>
</ul>

들여쓰기가 자동으로 한 단 깊어지면서, 안쪽 항목은 다른 모양의 점(보통 동그라미 ○)으로 바뀝니다.

인스타그램 메뉴는 어떤 목록일까?

다음 Step에서 만들 인스타그램 네비게이션 메뉴를 미리 상상해봅시다. 홈, 탐색, 피드, 프로필 네 항목이 있어요.

🤔 "순서가 의미를 만들까요?" 아니에요. 홈이 첫 번째이고 프로필이 마지막인 건 디자인 결정일 뿐, "홈을 먼저 봐야 프로필로 갈 수 있다"는 규칙은 없잖아요?

→ 그래서 메뉴는 **<ul>**로 만듭니다. 이건 거의 모든 웹사이트의 관례예요.

🙋 "메뉴는 점이 없던데요?" — 맞아요. CSS로 점을 제거하고 가로로 정렬한 거예요. 다음 모듈(B-2, B-3)에서 우리도 똑같이 할 거예요. 지금은 "메뉴는 의미상 ul"이라는 사실만 챙겨두세요.

<dl>이라는 친구도 있어요

목록의 사촌격으로 <dl>(Description List)도 있습니다. 용어와 그 설명을 짝지을 때 써요.

<dl>
  <dt>해시태그</dt>
  <dd>게시물 분류용 키워드 (#daily 등)</dd>

  <dt>스토리</dt>
  <dd>24시간 후 사라지는 짧은 게시물</dd>
</dl>

<dt>는 Term(용어), <dd>는 Description(설명)예요. 인스타그램 같은 SNS에서는 잘 안 쓰지만, 사전이나 용어집 페이지에서 자주 등장합니다. "이런 게 있구나" 정도만 알아두세요.

💡 직접 실험해보세요! <ul><ol>로 바꿔보세요. 점이 숫자로 변할 거예요. 다시 <ul>로 돌려놓고, <li> 안에 또 <ul>을 중첩해보세요. 들여쓰기가 깊어지는 게 보일 거예요.

🙋 학생 질문 — "li 없이 ul 안에 그냥 글자만 쓰면 안 되나요?"

문법상 안 됩니다. <ul><ol><li>만 자식으로 받기로 약속된 태그예요.

<!-- 잘못된 사용 -->
<ul>
  사진 공유
  스토리 올리기
</ul>

<!-- 올바른 사용 -->
<ul>
  <li>사진 공유</li>
  <li>스토리 올리기</li>
</ul>

브라우저는 첫 번째 코드도 어떻게든 보여주려고 노력하지만, 결과가 깨지거나 의도와 다르게 그려질 수 있어요. 스크린 리더도 "목록인데 항목이 없네?" 하고 당황합니다. 약속은 지키는 게 좋습니다.


Step 5: "웹을 웹답게 만드는 마법 — <a> 태그"

드디어 오늘 수업의 하이라이트입니다. 링크예요. HyperText Markup Language의 그 Hyper(초월하다, 넘나들다)가 의미하는 게 바로 이거예요. 페이지에서 페이지로 자유롭게 넘어다니는 능력.

링크가 없는 웹은 웹이 아니에요. 책 한 권만 있고 다른 책으로 갈 수 없는 도서관과 같습니다.

<a> 태그의 기본 문법

링크는 <a> 태그로 만듭니다. aAnchor(닻)의 약자예요. "여기에 닻을 박아 다른 페이지에 연결한다"는 의미예요.

<a href="profile.html">프로필 보러 가기</a>
  • <a> — 링크 태그
  • hrefHypertext REFerence (어디로 갈지)
  • "profile.html" — 목적지 주소
  • 프로필 보러 가기 — 화면에 표시될 텍스트 (클릭할 부분)

이 한 줄을 브라우저에 띄우면 "프로필 보러 가기"가 파란색 + 밑줄로 표시됩니다. 클릭하면 profile.html로 이동해요.

두 종류의 경로 — 절대 경로 vs 상대 경로

href 안에 들어가는 주소에는 두 종류가 있어요. 이 차이를 이해하는 게 오늘 가장 중요한 부분입니다.

절대 경로 (Absolute Path)

"전 세계 어디서 봐도 같은 곳"을 가리키는 주소입니다.

<a href="https://www.instagram.com">진짜 인스타그램</a>
<a href="https://www.google.com">구글</a>

https:// 로 시작해서 도메인 이름까지 다 적는 거예요. 다른 사이트로 이동할 때 씁니다. 우편 보낼 때의 "국가·도시·도로명·번지"까지 다 적는 주소라고 생각하면 됩니다.

상대 경로 (Relative Path)

"현재 페이지를 기준으로 한 위치"입니다.

<a href="profile.html">프로필</a>
<a href="feed.html">피드</a>

같은 폴더 안의 파일이면 그냥 파일명만 적어요. "같은 동네 안에서는 번지수만 알려줘도 찾아갈 수 있어" 같은 느낌이에요.

경로 표현 정리

조금 더 복잡한 경로 표현도 알아두면 좋아요.

표현 의미 예시
profile.html 같은 폴더 안의 파일 현재 폴더의 profile.html
./profile.html 같은 폴더 (명시적) 위와 동일
images/logo.png 하위 폴더의 파일 images/ 안의 logo.png
../index.html 상위 폴더의 파일 한 단계 위 폴더의 index.html
/index.html 사이트 최상위 도메인 루트의 index.html
https://... 절대 경로 다른 사이트

./ 은 "현재 폴더", ../ 는 "한 단계 위 폴더" 라고 기억하세요. 다음 시간에 이미지를 다룰 때 또 만날 표현들이에요.

새 탭에서 열기 — target="_blank"

링크를 클릭하면 기본적으로 현재 탭에서 페이지가 바뀝니다. 외부 사이트로 이동할 때는 "새 탭에서 열리게" 하고 싶을 때가 많아요.

<a href="https://github.com/instagram-clone"
   target="_blank"
   rel="noopener noreferrer">
  GitHub 저장소 보기
</a>
  • target="_blank" — 새 탭에서 열어줘
  • rel="noopener noreferrer" — 보안 옵션 (잠시 후 설명)

⚠️ rel="noopener noreferrer"는 외워두세요. target="_blank" 쓸 때 거의 항상 같이 붙이는 짝꿍입니다. 보안 이유 때문이에요.

🙋 "보안이라뇨? 그냥 새 탭 여는데요?" — 옛날 브라우저에는 "새 탭에서 연 페이지가 원래 탭을 마음대로 조작할 수 있는" 취약점이 있었어요. 악성 사이트가 원래 탭을 가짜 로그인 페이지로 바꿔치기 할 수 있었거든요. rel="noopener noreferrer"가 이 연결을 끊어줍니다.

요즘 브라우저는 자동으로 막아주지만, 호환성을 위해 명시하는 게 관례예요.

특수 링크 — 페이지 안에서, 메일로, 전화로

링크는 다른 페이지로만 가는 게 아니에요. 몇 가지 특수한 링크도 있습니다.

<!-- 페이지 안의 특정 영역으로 이동 -->
<a href="#help">도움말 영역으로 가기</a>

<!-- 메일 앱 열기 -->
<a href="mailto:contact@example.com">메일 보내기</a>

<!-- 전화 앱 열기 (모바일) -->
<a href="tel:+82-10-1234-5678">전화 걸기</a>

# 으로 시작하는 링크는 "같은 페이지의 특정 위치"로 점프합니다. 페이지가 길 때 맨 위로 가기 같은 자리에 유용해요. 어떤 요소에 id="help"가 붙어 있으면, <a href="#help">가 그 자리로 스크롤시켜줍니다.

mailto:tel: 은 모바일에서 특히 유용해요. 클릭하면 메일 앱이나 전화 앱이 자동으로 열려요.

직접 만들어보기

index.html의 안내 영역에 두 가지 링크를 추가해봅시다 — 비밀번호 찾기 링크와 회원가입 링크요.

<!-- instagram-clone-frontend/index.html -->
<section>
  <h2>친구들의 일상에 오신 것을 환영합니다</h2>
  <p>
    로그인하고 <strong>실시간</strong>으로
    친구들의 사진과 동영상을 확인하세요.
  </p>
  <p>
    <a href="#reset-password">비밀번호를 잊으셨나요?</a>
  </p>
</section>

저장하고 확인해보세요. "비밀번호를 잊으셨나요?"가 파란 밑줄로 표시되고, 마우스를 올리면 커서가 손가락 모양으로 바뀝니다. 클릭하면 — 아직 #reset-password라는 자리는 없으니 아무 일도 일어나지 않지만, "클릭 가능한 무언가가 됐다"는 사실이 보일 거예요.

💡 직접 실험해보세요! href="#reset-password"href="https://www.instagram.com"로 바꾸고 저장한 뒤 클릭해보세요. 진짜 인스타그램이 열려요!

🙋 학생 질문 — "절대 경로랑 상대 경로 중에 뭐가 더 좋아요?"

같은 사이트 안에서 이동할 때는 상대 경로가 권장됩니다. 이유는 두 가지예요.

  1. 사이트 이전이 쉬워요. 우리 사이트 주소가 localhost:5500에서 myinstagram.com으로 바뀌어도, 상대 경로는 손댈 게 없어요. 절대 경로로 박혀 있으면 전부 다 고쳐야 합니다.
  2. 로컬 개발이 편해요. Live Server에서 띄울 때 상대 경로는 그대로 동작합니다.

다른 사이트로 이동할 때는 절대 경로가 필수예요. https://github.com 같은 외부 도메인은 상대 경로로 표현할 방법이 없으니까요.


Step 6: "인스타그램 네비게이션 메뉴 만들기"

지난 시간에 약속드렸던 그것 — 네비게이션 메뉴입니다. 지금까지 배운 도구들이 한자리에 모이는 순간이에요.

메뉴를 구성하는 세 태그

인스타그램 메뉴는 세 태그의 조합으로 만듭니다.

<nav>  →  "이 영역은 메뉴예요"
  <ul>  →  "순서 없는 목록이에요"
    <li>  →  "메뉴 항목 하나"
      <a>  →  "다른 페이지로 가는 링크"

이 패턴은 거의 모든 웹사이트의 네비게이션 메뉴에 동일하게 등장해요. 한 번 익히면 평생 써먹는 패턴이에요.

빈 페이지부터 만들고 시작합시다

메뉴를 만들면 클릭했을 때 이동할 페이지가 있어야 동작을 확인할 수 있어요. 그래서 빈 페이지 두 개를 먼저 만듭니다.

instagram-clone-frontend 폴더에 다음 두 파일을 새로 만들어주세요.

feed.html (피드 페이지의 골격)

<!-- instagram-clone-frontend/feed.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Instagram - 피드</title>
</head>
<body>
  <header>
    <h1><a href="index.html">Instagram</a></h1>
  </header>

  <main>
    <h2>피드</h2>
    <p>친구들의 게시물이 여기에 표시됩니다.</p>
    <p><em>피드 카드와 좋아요 버튼은 다음 모듈(B-3)에서 본격적으로 만들어요.</em></p>
  </main>

  <footer>
    <p>&copy; 2026 Instagram Clone Project</p>
  </footer>
</body>
</html>

profile.html (프로필 페이지의 골격)

<!-- instagram-clone-frontend/profile.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Instagram - 프로필</title>
</head>
<body>
  <header>
    <h1><a href="index.html">Instagram</a></h1>
  </header>

  <main>
    <h2>프로필</h2>
    <p>사용자 프로필이 여기에 표시됩니다.</p>
  </main>

  <footer>
    <p>&copy; 2026 Instagram Clone Project</p>
  </footer>
</body>
</html>

두 파일 모두 골격만 잡아뒀어요. 본격 내용은 후속 모듈(B-3, B-4)에서 채울 예정입니다.

💡 로고도 링크로 만들었어요. <h1><a href="index.html">Instagram</a></h1> 부분 보이시죠? 인스타그램 로고를 클릭하면 항상 홈으로 돌아오는 관례를 따른 거예요. 모든 SNS·쇼핑몰·블로그가 이렇게 만듭니다.

<nav> 메뉴 추가하기

이제 세 페이지(index/feed/profile)의 <header> 안에 같은 메뉴를 추가합니다.

<header>
  <h1><a href="index.html">Instagram</a></h1>
  <nav>
    <ul>
      <li><a href="index.html">홈</a></li>
      <li><a href="explore.html">탐색</a></li>
      <li><a href="feed.html">피드</a></li>
      <li><a href="profile.html">프로필</a></li>
    </ul>
  </nav>
</header>

세 파일 모두에 똑같이 넣으면 어느 페이지에서든 메뉴로 페이지 이동이 가능한 상태가 됩니다.

⚠️ explore.html은 아직 만들지 않았어요. 클릭하면 "파일을 찾을 수 없습니다" 에러(404)가 뜰 거예요. 이건 정상이에요. 다음 모듈들에서 점점 채워나갈 페이지예요. 지금은 "링크는 걸려 있고, 페이지만 추가하면 곧장 동작한다"는 사실만 확인하세요.

동작 확인 — 페이지 사이를 클릭해서 이동해보기

세 파일을 저장하고 index.html을 Live Server로 열어보세요. 메뉴의 "피드"를 클릭 → 피드 페이지로 이동. 거기서 "프로필" 클릭 → 프로필 페이지로 이동. 로고 클릭 → 다시 로그인 페이지로 돌아옴.

이 순간이 오늘 수업의 하이라이트예요. "코드 한 줄로 페이지 이동이 동작한다." 인스타그램의 가장 기본적인 인터랙션이 손에 들어왔습니다.

<footer>에도 메뉴를 — 두 번째 <nav>

웹사이트들은 보통 풋터(바닥글)에도 메뉴가 있어요. 소개, 고객센터, 개인정보처리방침, 약관 같은 부가 정보 링크들이에요.

<footer>
  <nav>
    <ul>
      <li><a href="about.html">소개</a></li>
      <li><a href="help.html">고객센터</a></li>
      <li><a href="privacy.html">개인정보처리방침</a></li>
      <li><a href="terms.html">약관</a></li>
      <li>
        <a href="https://github.com/instagram-clone"
           target="_blank"
           rel="noopener noreferrer">
          GitHub
        </a>
      </li>
    </ul>
  </nav>
  <p>&copy; 2026 Instagram Clone Project</p>
</footer>

🙋 "한 페이지에 <nav>가 두 개 있어도 되나요?" — 네, 됩니다! 메뉴가 여러 곳에 있는 건 자연스러운 일이에요. 헤더에는 주요 페이지 메뉴, 풋터에는 부가 메뉴 — 이렇게 역할을 나누면 더 명확해집니다.

마지막 GitHub 링크에 target="_blank"rel="noopener noreferrer"가 같이 붙어 있는 거 보이시죠? Step 5에서 배운 외부 사이트 새 탭 열기 패턴이에요.

한 페이지에서 모든 게 합쳐진 모습

지금까지 만든 모든 걸 합쳐서, index.html의 헤더가 이런 모양이 됩니다.

<!-- instagram-clone-frontend/index.html -->
<header>
  <h1><a href="index.html">Instagram</a></h1>
  <nav>
    <ul>
      <li><a href="index.html">홈</a></li>
      <li><a href="explore.html">탐색</a></li>
      <li><a href="feed.html">피드</a></li>
      <li><a href="profile.html">프로필</a></li>
    </ul>
  </nav>
</header>

저장하고 브라우저를 확인해보세요. 헤더에 로고와 메뉴가 같이 보일 거예요. 아직 스타일이 없어서 메뉴가 세로로 점이 붙은 채로 나열되어 있을 텐데, 그건 의도된 결과예요. 다음 모듈(B-2/B-3)에서 CSS로 가로 정렬 + 점 제거를 해서 진짜 인스타그램처럼 만들어줄 거예요.

🙋 학생 질문 — "메뉴 4개가 다 ul 안에 있는데, 이걸 굳이 ul로 묶는 이유가 뭐예요? 그냥 a 태그 4개 나열하면 안 되나요?"

가능은 합니다. 이렇게 써도 동작은 해요.

<nav>
  <a href="index.html">홈</a>
  <a href="explore.html">탐색</a>
  <a href="feed.html">피드</a>
  <a href="profile.html">프로필</a>
</nav>

그런데 권장되지 않아요. 이유 두 가지.

  1. 스크린 리더가 "메뉴 4개"를 한 묶음으로 인식하지 못합니다. <ul>로 묶으면 "목록, 항목 4개"라고 안내해줘요.
  2. 나중에 CSS로 스타일링할 때 어려워집니다. 각 항목을 li 단위로 묶어두면 "i번째 항목", "마지막 항목" 같은 정밀한 스타일이 가능해요.

"의미가 같은 항목의 묶음 = 목록 = <ul>/<ol>" — 이 공식을 기억하세요.


Step 7: "로그인 페이지 마무리 — 회원가입 + 비밀번호 찾기"

지난 시간 과제 기억나세요? "<main> 안에 <section>을 하나 더 추가해서 회원가입 안내 영역을 만들어보세요" 였죠. 오늘 그 영역에 실제 동작하는 링크를 박아 넣을 거예요. 약속한 회수입니다.

회원가입 안내에 링크 달기

지난 시간 과제로 추가했던 회원가입 <section> 안의 텍스트를 <a> 태그로 감싸봅시다.

<!-- instagram-clone-frontend/index.html -->
<section>
  <p>계정이 없으신가요? <strong><a href="signup.html">가입하기</a></strong></p>
  <p>가입은 <mark>30초</mark>면 충분합니다. <em>지금 바로</em> 시작해보세요.</p>
</section>

여기서 재미있는 자리가 두 군데 있어요.

1. <strong><a>를 같이 쓴 자리

<strong><a href="signup.html">가입하기</a></strong>

"가입하기"는 링크이자 중요한 행동 유도예요. 두 의미를 동시에 표현하려고 <strong>으로 한 번 더 감쌌습니다. 굵게 + 파란 밑줄 + 클릭 가능 — 세 효과가 한 번에 적용돼요.

2. <mark><em>이 같이 등장한 자리

"가입은 30초면 충분합니다. 지금 바로 시작해보세요."

<mark>(노란 형광펜)와 <em>(기울임)이 한 문단에 같이 있어요. 시선을 끄는 부분 + 어조를 살리는 부분이 자연스럽게 어울립니다.

비밀번호 찾기 링크 추가

로그인 영역에는 "비밀번호를 잊으셨나요?" 링크가 거의 항상 있어요. Step 5에서 미리 박아둔 코드를 다시 확인해봅시다.

<section>
  <h2>친구들의 일상에 오신 것을 환영합니다</h2>
  <p>
    로그인하고 <strong>실시간</strong>으로
    친구들의 사진과 동영상을 확인하세요.
  </p>
  <p>
    <a href="#reset-password">비밀번호를 잊으셨나요?</a>
  </p>
  <!-- 로그인 폼은 A-4 모듈에서 추가합니다 -->
</section>

href="#reset-password"는 "페이지 안의 #reset-password 위치로 이동"이라는 뜻이에요. 비밀번호 재설정 영역은 다음 모듈(A-4)에서 폼과 함께 만들 예정이라, 지금은 자리만 잡아둔 상태예요.

🙋 "클릭하면 아무 일도 안 일어나는데요?" — 맞아요. #reset-password라는 id가 붙은 요소가 아직 없으니까요. "링크는 동작하지만 목적지가 없는 상태"예요. A-4에서 폼을 만들 때 자연스럽게 연결됩니다.

풋터 메뉴까지 합쳐서 완성된 모습

오늘 작업한 모든 변경 사항을 합치면, index.html은 이렇게 모양이 잡힙니다.

<!-- instagram-clone-frontend/index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Instagram - 로그인</title>
</head>
<body>
  <header>
    <h1><a href="index.html">Instagram</a></h1>
    <nav>
      <ul>
        <li><a href="index.html">홈</a></li>
        <li><a href="explore.html">탐색</a></li>
        <li><a href="feed.html">피드</a></li>
        <li><a href="profile.html">프로필</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <section>
      <h2>친구들의 일상에 오신 것을 환영합니다</h2>
      <p>
        로그인하고 <strong>실시간</strong>으로
        친구들의 사진과 동영상을 확인하세요.
      </p>
      <p>
        <a href="#reset-password">비밀번호를 잊으셨나요?</a>
      </p>
      <!-- 로그인 폼은 A-4 모듈에서 추가합니다 -->
    </section>

    <hr>

    <section>
      <p>계정이 없으신가요? <strong><a href="signup.html">가입하기</a></strong></p>
      <p>가입은 <mark>30초</mark>면 충분합니다. <em>지금 바로</em> 시작해보세요.</p>
    </section>
  </main>

  <footer>
    <nav>
      <ul>
        <li><a href="about.html">소개</a></li>
        <li><a href="help.html">고객센터</a></li>
        <li><a href="privacy.html">개인정보처리방침</a></li>
        <li><a href="terms.html">약관</a></li>
        <li><a href="https://github.com/instagram-clone" target="_blank" rel="noopener noreferrer">GitHub</a></li>
      </ul>
    </nav>
    <p>&copy; 2026 Instagram Clone Project</p>
  </footer>
</body>
</html>

저장하고 브라우저를 확인하면 — 오늘 배운 모든 요소가 한 페이지에 다 모여 있어요.

  • 제목 위계: <h1> Instagram + <h2> 환영 메시지
  • 문단과 강조: <p> 안의 <strong> / <mark> / <em>
  • 영역 구분: 두 <section> 사이의 <hr>
  • 메뉴: 헤더의 메인 메뉴 + 풋터의 부가 메뉴 (<nav> × 2)
  • 링크: 내부 페이지 + 외부 사이트 + 페이지 내 앵커

DevTools로 검사해보기

지난 시간 마지막에 잠깐 본 Chrome DevTools를 다시 열어봅시다. (F12 또는 Cmd+Option+I)

Elements 탭에서 <nav>, <ul>, <li>, <a> 태그가 트리 구조로 펼쳐지는 모습을 보세요. 마우스를 올리면 해당 영역이 브라우저 화면에서 파란색으로 하이라이트됩니다.

특히 "링크 위에 마우스를 올렸을 때 브라우저 하단 모서리에 표시되는 작은 주소"에 주목해보세요. 우리가 href에 적은 그 주소가 보일 거예요. 절대 경로 링크는 "https://..." 로, 상대 경로는 현재 도메인이 자동으로 붙어서 보입니다.


마무리

오늘 배운 핵심 다섯 가지

🎯 하나, 제목은 <h1>부터 <h6>까지 위계가 있는 6단계입니다. 한 페이지에 <h1>은 하나, 크기는 CSS로 조절.

🎯 , 문단은 <p>, 줄바꿈은 <br>, 주제 전환은 <hr> — 셋의 의미가 다릅니다. 닫는 태그가 없는 빈 요소(Empty Element) 개념도 만났어요.

🎯 , 강조에는 의미가 담깁니다. <strong>은 중요, <em>은 어조, <mark>는 형광펜. 모양만 정하는 <b>, <i>는 권장되지 않아요.

🎯 , 목록은 <ul>(점) / <ol>(숫자), 항목은 <li>. 메뉴는 거의 항상 <ul>로 만듭니다.

🎯 다섯, <a href="..."> 가 웹을 웹답게 만드는 마법입니다. 상대 경로(profile.html)와 절대 경로(https://...)를 구분해서 쓰고, 외부 링크에는 target="_blank" + rel="noopener noreferrer" 짝꿍을 잊지 마세요.

오늘 손에 들어온 인스타그램 상태

  • ✅ 로그인 페이지 (index.html) — 제목 위계 + 강조 + 회원가입/비밀번호 링크
  • ✅ 피드 페이지 골격 (feed.html) — 다음 모듈에서 본격 작성 예정
  • ✅ 프로필 페이지 골격 (profile.html) — 다음 모듈에서 본격 작성 예정
  • ✅ 헤더의 네비게이션 메뉴 — 세 페이지 사이를 클릭해서 오갈 수 있음
  • ✅ 풋터의 부가 메뉴 — 외부 GitHub 링크 포함

다음 시간 예고

오늘까지는 텍스트와 링크였어요. 그런데 인스타그램이 인스타그램인 이유는 사진이잖아요? 다음 시간에는 페이지에 이미지를 박는 법을 배웁니다.

  • <img> 태그와 src, alt 속성
  • loading="lazy" — 스크롤 내려가야 이미지가 로드되는 트릭
  • <video> 태그로 동영상 임베드
  • <figure> + <figcaption>으로 캡션이 달린 이미지

오늘 빈 골격으로 만든 feed.html에 진짜 게시물 이미지가 들어가기 시작할 거예요. 프로필 페이지에는 아바타가 추가되고요.


과제

[구현] 회원가입 페이지 골격 만들기

signup.html 파일을 새로 만들어보세요. 오늘 만든 feed.html/profile.html 처럼 빈 골격 페이지면 됩니다.

요구 사항:

  • <header>에 인스타그램 로고(<h1> + 링크) + 메인 메뉴(<nav> + <ul> + <a>) 포함
  • <main> 안에 <h2> 회원가입 제목 + 안내 문구 <p> 1~2개
  • <footer> 포함
  • index.html의 "가입하기" 링크(href="signup.html")를 클릭하면 이 페이지로 이동하는지 확인
  • signup.html에서 다시 "홈" 메뉴를 클릭해서 로그인 페이지로 돌아오는지 확인

가입 안내 문구에는 오늘 배운 텍스트 강조 태그 두 종류 이상을 넣어보세요.

[탐구] 좋아하는 웹사이트 3곳의 네비게이션 메뉴 분석하기

자주 가는 웹사이트 3곳을 열고 F12로 Elements 탭을 봐주세요. 헤더의 메인 메뉴 부분을 찾아서 다음을 확인합니다.

  1. 메뉴를 <nav> 안에 넣었나요? 아니면 <div>로만 되어 있나요?
  2. 메뉴 항목을 <ul> + <li>로 묶었나요? 아니면 <a>만 나열했나요?
  3. 풋터에도 별도 <nav>가 있나요?
  4. 외부 사이트로 가는 링크에 target="_blank"가 붙어 있나요? rel="noopener noreferrer"도 같이 있나요?

세 사이트의 결과를 간단히 표로 정리하고, "가장 시멘틱하게 만든 사이트는 어디였는가" 자기 의견을 한 줄 덧붙여주세요.


생각해볼 주제

1. 메뉴를 <ul>로 묶는 게 진짜로 필요한가?

브라우저에서 보면 <ul>로 묶으나 <a>만 나열하나 겉모습은 거의 같아 보일 수 있습니다. CSS로 점만 없애면 더 그렇고요. 그런데도 거의 모든 가이드라인은 "메뉴는 <ul> + <li> + <a>로 묶어라"고 권장해요.

이 권장의 이유는 무엇일까요? 접근성, 유지보수성, CSS 정밀도 세 키워드를 떠올리면서, 시멘틱 마크업이 눈에 보이지 않는 가치를 어떻게 만드는지 정리해보세요.

2. target="_blank"는 사용자에게 친절한 기본값일까?

링크를 새 탭에서 여는 target="_blank"는 "사용자가 원래 페이지를 잃지 않게" 하는 배려처럼 보입니다. 그런데 일부 접근성 가이드라인은 "기본은 같은 탭, 새 탭은 사용자의 선택에 맡겨라"고 조언해요.

어떤 자리에 target="_blank"가 어울리고, 어떤 자리에는 어울리지 않을까요? 모바일에서 뒤로가기 버튼, 스크린 리더 사용자의 혼란, 외부 사이트 신뢰성 같은 관점을 떠올리면서 자기 기준을 만들어보세요.

3. 만약 HTML에 링크가 없었다면?

HTML의 Hyper (초월하다) 가 의미하는 게 링크인데, 만약 이 기능이 없었다면 웹은 어떤 모습이었을까요? 사용자는 페이지를 어떻게 옮겨다녔을까요? 검색엔진은 어떻게 사이트들을 연결했을까요?

링크가 만들어낸 "웹의 연결성"이 단순히 클릭 한 번의 편의를 넘어 무엇을 가능하게 했는지 자기 언어로 정리해보세요. 위키피디아, 블로그, SNS 공유 같은 일상의 자리에서 출발해도 좋아요.

✅ 예시 답안정답 보기

🎯 [과제 1 예시답안] 회원가입 페이지 골격 만들기

채점 포인트

항목 배점 기준
signup.html 파일 생성 15% 폴더에 새 파일이 만들어졌는가
HTML 보일러플레이트 15% <!DOCTYPE>, <html lang>, <head>(meta + title), <body> 구조
<header> 로고 + <nav> 메뉴 25% 세 페이지 공통 헤더 패턴이 적용됐는가 (<h1> + <a> 로고 + <nav> + <ul> + <li> + <a>)
<main><h2> + 안내 문단 20% 회원가입 제목과 안내 문구가 있는가
텍스트 강조 태그 2종 이상 15% <strong>, <em>, <mark> 중 둘 이상 사용
페이지 이동 확인 10% index.htmlsignup.html 양방향 이동이 동작하는가

완성 코드

<!-- instagram-clone-frontend/signup.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Instagram - 회원가입</title>
</head>
<body>
  <header>
    <h1><a href="index.html">Instagram</a></h1>
    <nav>
      <ul>
        <li><a href="index.html">홈</a></li>
        <li><a href="explore.html">탐색</a></li>
        <li><a href="feed.html">피드</a></li>
        <li><a href="profile.html">프로필</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <section>
      <h2>친구들과 일상을 공유해보세요</h2>
      <p>
        가입은 <mark>30초</mark>면 충분합니다.
        <strong>이메일</strong>과 <strong>닉네임</strong>만 있으면 시작할 수 있어요.
      </p>
      <p>
        이미 계정이 있으신가요? <em>그렇다면</em>
        <a href="index.html">로그인 페이지</a>로 돌아가세요.
      </p>
      <!-- 회원가입 폼은 A-4 모듈에서 추가합니다 -->
    </section>
  </main>

  <footer>
    <p>&copy; 2026 Instagram Clone Project</p>
  </footer>
</body>
</html>

💡 튜터의 포인트

핵심은 세 가지 패턴이 한 페이지에 다 들어왔는가 입니다.

  1. 시멘틱 골격<header> / <main> / <footer> 영역 구분 (A-1에서 배운 것)
  2. 공통 네비게이션 — 헤더의 메뉴는 세 페이지가 동일한 구조 (A-2 Step 6에서 배운 것)
  3. 텍스트 강조<strong>, <em>, <mark> 중 둘 이상 (A-2 Step 3에서 배운 것)

특히 헤더의 메뉴를 그대로 복붙하면 됩니다. 이게 정답이에요. 세 페이지에 같은 메뉴가 들어 있어야 어디서든 다른 페이지로 이동할 수 있거든요.

🙋 "메뉴 항목에 '회원가입'은 안 넣어요?" — 좋은 질문입니다. 메인 메뉴는 로그인 사용자가 자주 가는 자리에 맞춰 디자인해요. 회원가입은 비로그인 사용자만 가는 자리라 메인 메뉴보다는 본문 안의 "가입하기" 같은 행동 유도 링크로 처리하는 게 관례예요. 우리도 그 관례를 따라 메뉴에 회원가입을 안 넣었습니다.

또 한 가지 — signup.html을 만들면 index.html의 "가입하기" 링크가 진짜로 동작합니다. 클릭 → 회원가입 페이지로 이동 → 홈 메뉴 클릭 → 로그인으로 복귀. 이 사이클이 돌아간다면 100점이에요.


🎯 [과제 2 예시답안] 좋아하는 웹사이트 3곳의 네비게이션 메뉴 분석하기

채점 포인트

항목 배점 기준
3곳 이상 분석 20% 서로 다른 웹사이트 3곳을 조사했는가
<nav> 사용 여부 20% 메인 메뉴가 <nav> 안에 있는지 확인
<ul> + <li> 구조 여부 20% 메뉴 항목이 목록 구조로 묶여 있는지 확인
풋터 <nav> 여부 15% 풋터에도 별도 메뉴가 있는지 확인
외부 링크 target="_blank" + rel 15% 외부 사이트 링크 처리 확인
자기 의견 한 줄 10% "가장 시멘틱한 사이트" 평가 근거 제시

조사 예시

여러분이 직접 확인한 결과와 다를 수 있어요. 이 예시는 형식을 보여드리는 거예요.

웹사이트 헤더 <nav> 헤더 <ul>/<li> 풋터 <nav> target="_blank" + rel
GitHub O O O O (외부 docs 링크)
Naver O △ (<div>/<a> 혼용) O △ (일부에만 rel 누락)
개인 블로그 A X (<div>로만 구성) X (<a> 나열) X X

💡 튜터의 포인트

조사 결과에서 "의외의 발견"이 있었을 거예요. 큰 회사의 사이트도 완벽하게 시멘틱하지는 않다는 사실이요.

세 가지 패턴이 자주 나옵니다.

패턴 A: 모범생 사이트 (GitHub, MDN, GOV.UK 등)

  • 헤더/풋터에 <nav> 명시
  • 메뉴는 <ul> + <li> + <a> 패턴
  • 외부 링크에 rel="noopener noreferrer" 일관 적용
  • 접근성·시멘틱을 조직 차원에서 신경 쓰는 사이트

패턴 B: 절반 모범생 (대형 포털, 쇼핑몰 등)

  • <nav>는 있지만 안쪽은 <div> + <a> 혼용
  • 디자인 자유도를 위해 시멘틱을 일부 포기한 경우
  • 풋터 메뉴는 <nav> 없이 <div>로만 처리

패턴 C: 시멘틱 무관심 사이트 (오래된 사이트, 개인 블로그 등)

  • 전부 <div> + <a>
  • "동작만 하면 됐지" 마인드
  • 검색엔진 노출과 접근성에서 손해

🙋 "그럼 가장 모범적인 사이트는 어디였어요?" — 흔히 MDN Web Docs (developer.mozilla.org)가 꼽힙니다. 시멘틱 마크업을 교과서처럼 사용해서 학습용 참고 자료로도 좋아요. 시간 나실 때 한 번 F12로 구조를 둘러보세요.

여러분의 코드는 어떤 패턴에 속할지 떠올려보는 게 이 과제의 진짜 목적이에요. "나는 모범생 사이트를 만드는 개발자가 되겠다"는 마음만 챙기시면 됩니다.


🤔 [생각해볼 주제 1 예시답안] 메뉴를 <ul>로 묶는 게 진짜로 필요한가?

[문제 상황 요약]

겉모습은 비슷한 두 코드.

<!-- A: ul로 묶기 -->
<nav>
  <ul>
    <li><a href="home">홈</a></li>
    <li><a href="feed">피드</a></li>
  </ul>
</nav>

<!-- B: a만 나열 -->
<nav>
  <a href="home">홈</a>
  <a href="feed">피드</a>
</nav>

CSS로 점만 제거하면 시각적으로 거의 같아 보입니다. 그런데도 거의 모든 가이드는 "A 패턴을 써라"고 권장합니다.

[튜터의 가이드 및 해설]

세 가지 관점에서 "눈에 보이지 않는 가치"가 만들어집니다.

1. 접근성 — 스크린 리더의 안내가 달라진다

스크린 리더는 <ul>을 만나면 사용자에게 이렇게 안내해요.

"목록, 항목 4개. 항목 1, 홈. 항목 2, 피드. ..."

<ul> 없이 <a>만 나열하면:

"링크, 홈. 링크, 피드. 링크, ..."

차이가 보이시죠? 첫 번째는 "메뉴가 총 몇 개인지"를 미리 알려줘서 사용자가 "피드는 두 번째 항목이니까 한 번 더 탭하면 되겠네"라고 예상할 수 있어요. 두 번째는 끝까지 다 들어봐야 합니다.

또 스크린 리더에는 랜드마크 점프 기능이 있어요. <nav>로 점프 → 그 안의 <ul> 시작점부터 안내. 구조가 명확할수록 사용자가 더 빨리 원하는 곳에 도달합니다.

2. 유지보수성 — 일관된 패턴이 미래의 나를 살린다

지금 우리 사이트엔 메뉴 항목이 4개예요. 6개월 후에 "검색" 메뉴를 추가한다고 해봅시다.

A 패턴이면:

<li><a href="search">검색</a></li>

한 줄만 끼워 넣으면 끝이에요.

B 패턴이면:

<a href="search">검색</a>

이것도 한 줄이지만, CSS로 "각 메뉴 사이 간격"을 어떻게 처리하는지에 따라 무너질 수 있어요. <li>로 묶여 있으면 "li 사이의 간격"이라는 일관된 규칙으로 처리하지만, <a>만 있으면 "a와 a 사이 간격"이 어떻게 정의됐는지 매번 확인해야 합니다.

패턴이 일관되면 변경이 안전하다 — 이게 유지보수성의 핵심이에요.

3. CSS 정밀도 — <li> 단위로 정밀하게 스타일링 가능

CSS에는 "여러 항목 중 N번째", "마지막 항목", "첫 번째 항목" 같은 정밀한 선택자가 있어요.

nav li:first-child { /* 첫 메뉴만 */ }
nav li:last-child  { /* 마지막 메뉴만 */ }
nav li:nth-child(3) { /* 세 번째 메뉴만 */ }

이런 정밀 선택자는 항목이 같은 구조로 묶여 있을 때만 안전하게 동작해요. <a>만 나열하면 "첫 번째 a"가 어디인지가 부모 안의 위치에 따라 흔들립니다. 옆에 다른 a가 끼면 인덱스가 어긋나거든요.

결론 — 겉모습이 같다는 건 지금 이 순간만 같다는 뜻

시멘틱 마크업의 가치는 "지금 눈에 보이는 결과"가 아니라 시간이 흐르고, 사용자가 바뀌고, 기능이 추가될 때 드러나는 안정성에 있어요. 메뉴를 <ul>로 묶는 작은 습관이 접근성·유지보수·CSS 정밀도를 동시에 챙기는 셈입니다.

🎯 면접관을 홀리는 핵심 멘트

"메뉴를 <ul>로 묶는 건 지금 눈에 보이는 결과가 아니라 세 가지 미래를 위한 투자입니다. 첫째, 스크린 리더가 '항목 N개'를 미리 안내해서 접근성이 살아납니다. 둘째, 항목 추가/삭제가 일관된 패턴이라 유지보수가 안전해집니다. 셋째, :first-child, :nth-child 같은 CSS 정밀 선택자가 안전하게 동작합니다. 결국 시멘틱 마크업은 눈에 보이지 않는 사용자와 미래의 동료를 위한 코드예요."


🤔 [생각해볼 주제 2 예시답안] target="_blank"는 사용자에게 친절한 기본값일까?

[문제 상황 요약]

새 탭에서 링크를 여는 target="_blank"는 "원래 페이지를 잃지 않게" 배려하는 것처럼 보입니다. 그런데 Nielsen Norman Group 같은 UX 연구 기관과 W3C 접근성 가이드라인은 "기본은 같은 탭, 새 탭은 신중히"를 권장해요.

[튜터의 가이드 및 해설]

새 탭 열기를 기본으로 삼는 게 문제가 되는 자리가 있어요.

1. 모바일 — 뒤로가기가 막힌다

데스크톱에서 target="_blank"는 별 문제가 없어요. 새 탭이 옆에 생기고, 닫으면 원래 자리로 돌아가니까요.

문제는 모바일입니다. 모바일 브라우저는 탭 전환 UI가 작고 숨겨져 있어요. 사용자는 보통 뒤로가기 버튼으로 페이지를 오갑니다. 그런데 target="_blank"로 열린 새 탭에는 뒤로가기가 동작하지 않아요 — 새 탭의 첫 페이지니까요.

결과: 사용자는 "뒤로가기를 눌렀는데 아무 일도 안 일어남" → "앱이 멈췄나?" → 이탈.

2. 스크린 리더 사용자 — 예고 없이 탭이 바뀐다

시각 장애인 사용자가 링크를 클릭했는데, 갑자기 완전히 다른 페이지에서 안내가 시작된다고 상상해보세요. "어, 내가 다른 페이지에 와 있다고? 뒤로가기를 어떻게 하지?"

접근성 가이드라인 WCAG 2.2는 "새 탭에서 열린다는 사실을 사전 안내하지 않으면 곤란"하다고 명시해요. target="_blank"를 쓸 때는 보통 시각적으로 "외부 링크 아이콘"을 옆에 붙이거나, "새 탭에서 열림"이라는 텍스트를 명시하는 게 권장됩니다.

3. 사용자의 선택권 침해

데스크톱 사용자는 이미 "새 탭에서 열기"를 자기 의지로 선택할 수 있어요. 중간 클릭, Cmd+클릭(맥), Ctrl+클릭(윈도우) — 다 새 탭으로 엽니다. 그런데 모든 링크에 target="_blank"를 박아두면 사용자의 선택권을 개발자가 빼앗아가는 셈이에요.

"내가 같은 탭에서 보고 싶었는데, 사이트가 강제로 새 탭을 띄웠다"는 불만이 여기서 나옵니다.

그럼 언제 target="_blank"가 적절한가?

세 가지 경우 정도에 어울려요.

  1. 외부 사이트로 이동할 때 — 사용자가 내 사이트에서 이탈하지 않게 새 탭에서 열기. (예: GitHub 저장소, 외부 문서)
  2. 현재 작업이 중단되면 곤란한 자리 — 폼을 작성 중인데 외부 약관을 띄울 때. 같은 탭이면 폼 내용이 날아갈 수 있어요.
  3. PDF, 큰 이미지 등 새 창에서 보는 게 자연스러운 자료

반대로 같은 사이트 안의 페이지 이동에는 target="_blank"쓰지 않는 게 기본입니다. 우리 인스타그램 프로젝트도 메인 메뉴 4개는 같은 탭에서 이동하고, 풋터의 GitHub 링크만 새 탭으로 열게 한 이유가 이거예요.

🎯 면접관을 홀리는 핵심 멘트

"target='_blank'는 모든 자리에 친절한 기본값이 아닙니다. 모바일의 뒤로가기 동선 단절, 스크린 리더 사용자에게 예고 없는 컨텍스트 전환, 데스크톱 사용자의 선택권 침해 — 세 가지 비용이 있어요. 적절한 자리는 외부 사이트 이동, 작업 중단을 막아야 하는 보조 자료, PDF 같은 별도 매체 정도입니다. 같은 사이트 내부 이동은 같은 탭이 기본이고, 새 탭 여는 자리에는 rel='noopener noreferrer' 보안 짝꿍을 잊으면 안 됩니다."


🤔 [생각해볼 주제 3 예시답안] 만약 HTML에 링크가 없었다면?

[문제 상황 요약]

HTML의 Hyper가 의미하는 게 바로 "넘나든다, 초월한다"는 뜻의 링크예요. 이게 없었다면 웹은 어떤 모습이었을까요?

[튜터의 가이드 및 해설]

링크 없는 웹을 상상해봅시다. 모든 페이지는 고립된 섬이에요.

1. 사용자의 페이지 이동 — 주소를 외워야 한다

링크가 없으면 사용자는 페이지 이동을 어떻게 할까요? 주소창에 URL을 직접 타이핑해야 합니다.

"인스타그램 로그인 페이지를 보려면 https://www.instagram.com/accounts/login을 외우세요."

이건 책입니다. 도서관에서 다른 책을 보려면 자리에서 일어나 새 책을 꺼내 와야 하는 그 도서관이에요. 연결이 끊긴 정보의 모음이지, 유기적으로 이어진 지식 네트워크가 아니에요.

2. 검색엔진 — 애초에 존재할 수 없다

구글, 네이버 같은 검색엔진의 핵심 기술은 "링크 따라가기"예요. 크롤러라는 프로그램이 페이지를 방문해서 그 안의 모든 <a href>를 그 다음 방문지 목록으로 삼아 다음 페이지로 넘어갑니다.

링크가 없으면? 크롤링이 불가능해요. 검색엔진은 세상의 모든 페이지 URL을 누군가가 일일이 알려줘야만 인덱싱할 수 있는데, 그건 현실적으로 불가능합니다.

"구글의 PageRank 알고리즘은 링크의 그물망을 분석해서 어떤 페이지가 더 중요한지를 계산해요. 링크가 많이 들어오는 페이지일수록 중요한 페이지로 판단합니다. 링크가 없으면 이 알고리즘 자체가 성립하지 않아요."

3. 위키피디아 — 영영 만들어지지 않았을 것

위키피디아 한 문서를 열어보면, 본문 한 문단에 링크가 수십 개예요. "제2차 세계대전" 문서를 읽다가 "히틀러" 링크를 클릭하면 곧장 히틀러 문서로, 거기서 "나치즘" 클릭으로, 다시 "독일 제국" 클릭으로… 지식이 그물처럼 펼쳐집니다.

링크가 없었다면 위키피디아는 수만 권의 백과사전 책에 불과해요. 한 권 다 읽어도 다른 책으로 넘어가는 길이 없는 백과사전. 그건 위키피디아가 아닙니다.

4. SNS의 공유 — 불가능했을 것

"이 글 좋네! 친구에게 공유해야지" 하고 인스타그램 스토리에 링크를 올리는 일상. 이게 다 링크가 있는 덕분이에요. 링크가 없으면 "이 글의 URL을 손으로 받아 적어"가 됩니다. 공유 문화 자체가 성립이 안 돼요.

그럼 링크의 진짜 의미는?

링크는 클릭 한 번의 편의가 아닙니다. 그건 표면이고, 그 아래엔 더 깊은 게 있어요.

링크는 정보를 네트워크화합니다.

연결되지 않은 정보 1000개는 그냥 고립된 점 1000개예요. 하지만 링크로 연결된 정보 1000개는 서로 참조하고, 검증하고, 확장하는 그물망이 됩니다. 인류 지식이 기하급수적으로 누적되기 시작한 게 정확히 웹이 등장한 이후인 이유가 이거예요.

링크는 단순한 기능이 아니라 "정보의 위상수학을 바꾸는 발명"입니다. 우리가 <a> 태그 한 줄을 쓸 때마다, 사실은 인류의 지식 그물에 새로운 실 한 가닥을 더하는 일을 하고 있는 거예요.

🎯 면접관을 홀리는 핵심 멘트

"링크가 없었다면 웹은 연결되지 않은 책의 도서관에 불과했을 거예요. 사용자는 모든 페이지 주소를 외워야 했고, 검색엔진은 링크 따라가기를 못 해서 애초에 존재할 수 없었어요. 위키피디아 같은 지식 네트워크도, SNS 공유 문화도 다 링크에서 시작됩니다. <a> 태그 한 줄은 클릭 한 번의 편의가 아니라 정보의 위상수학을 바꾸는 발명이에요. 그래서 HTML의 Hyper가 Markup보다 먼저 붙어 있는 거고요."

더 배우려면

실무 프로젝트까지 가고 싶다면

팀스파르타 백엔드 부트캠프에서 인스타그램 클론을 풀스택으로 완성합니다.