Skip to Content
WebHTMLHTML 기본기17. 다음 과목 예고: css_fundamentals로 넘어가기 전에

이번 편의 결과물: 디자인 시안과 자신의 무스타일 마크업을 나란히 확인하고, css_fundamentals 01편에서 이어받을 파일 경로를 안내받는다. · 다루는 개념: 마크업이 스타일링 대상이 되는 방식, 디자인 시안과 현재 마크업 비교, class/id 네이밍이 선택자 설계에 미치는 영향

이 편에서 만드는 파일

web-practice/portfolio/ ├ index.html (최종 상태 확인 — 이 편의 정본 코드) ├ projects.html (최종 상태 확인 — 이 편의 정본 코드) └ contact.html (최종 상태 확인 — 이 편의 정본 코드)

개념 정리

지금까지 만든 세 파일에는 스타일이 하나도 없지만, 요소마다 class가 이미 붙어 있다. 이 class들은 css_fundamentals가 선택자로 그대로 쓸 이름이다. 지금 이름을 지어 둔 덕분에 다음 과목은 마크업을 다시 건드리지 않고 css/tokens.css·css/styles.css 두 파일만 새로 만들면 된다.

지금 붙인 class/idcss_fundamentals에서 하는 일
.site-header상단 고정(position: sticky), 높이·배경·테두리 지정
.logo글자 크기·굵기 지정
.site-nav가로 배치(Flexbox), 링크 간격 지정
.hero세로 여백, 제목 크기, 버튼 스타일
.about프로필 사진과 문단의 배치(Flexbox/Grid)
.skills정의 목록을 카드형으로 배치
.career표 헤더 배경, 행 구분선
.project-gridGrid 레이아웃(모바일 1열 → 데스크톱 3열)
.project-card배경·테두리·hover 그림자 전환
.contact-form필드 간격, 포커스 링, 오류 상태 테두리
.site-footer배경·여백·SNS 링크 배치

css_fundamentals는 이 이름들의 뜻을 바꾸지 않는다. .project-card는 계속 프로젝트 카드를 가리키고, CSS는 그 카드를 어떻게 보여줄지만 정한다. 이것이 HTML(구조)과 CSS(표현)를 나누는 이유다.

시안(design-spec.md)과 지금 마크업을 나란히 보면 색·간격·글꼴이 전부 비어 있을 뿐, 어떤 콘텐츠가 어디 있는지는 이미 시안과 같은 순서다. 다음 과목은 이 순서를 바꾸지 않고 겉모습만 입힌다.

실습

1. 디자인 시안과 현재 마크업 나란히 보기

public/practice/portfolio/design-spec.md의 “1. 사이트 구성” 표와 지금 작성한 세 파일의 섹션 순서를 비교한다. index.html은 히어로 → 소개 → 기술 스택 → 경력, projects.html은 카드 그리드, contact.html은 폼 → 연락처 정보 순서로 이미 일치한다.

2. 세 파일의 완성 상태를 정본으로 확인

아래는 이 시점의 index.html·projects.html·contact.html 전체 코드다. 지금까지 작업한 파일과 한 줄씩 대조한다.

<!-- web-practice/portfolio/index.html --> <!doctype html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Zeno Kim — 소개</title> </head> <body> <header class="site-header"> <a class="logo" href="index.html">Zeno Kim</a> <nav class="site-nav" aria-label="주 메뉴"> <ul> <li><a href="index.html" aria-current="page">소개</a></li> <li><a href="projects.html">프로젝트</a></li> <li><a href="contact.html">연락</a></li> </ul> </nav> </header> <main> <section class="hero" id="hero"> <h1>웹을 만드는 개발자, Zeno Kim입니다.</h1> <p>HTML·CSS·JavaScript로 누구나 쓸 수 있는 화면을 만듭니다.</p> <a class="button" href="projects.html">프로젝트 보기</a> <a class="button" href="contact.html">연락하기</a> </section> <section class="about" id="about"> <h2>소개</h2> <img src="images/profile.svg" alt="Zeno Kim의 프로필 사진" width="400" height="400" /> <p> 저는 3년째 프론트엔드를 공부하고 만들고 있습니다. 화면이 예뻐 보이는 것보다 <strong>누가 봐도 쓸 수 있는가</strong>를 먼저 생각합니다. </p> <p> 처음에는 디자인 툴로 화면을 그리다가, 직접 만들어 보고 싶어서 HTML과 CSS를 배웠습니다. 지금은 React로 서비스 화면을 만들고 있습니다. </p> <p>접근성과 웹 표준을 좋아합니다. 스크린 리더로 제 사이트를 읽어 보는 일이 습관이 됐습니다.</p> </section> <section class="skills" id="skills"> <h2>기술 스택</h2> <dl> <dt>마크업·스타일</dt> <dd>HTML</dd> <dd>CSS</dd> <dd>Sass</dd> <dt>언어</dt> <dd>JavaScript</dd> <dd>TypeScript</dd> <dt>프레임워크</dt> <dd>React</dd> <dd>Next.js</dd> <dt>도구</dt> <dd>Git</dd> <dd>Vite</dd> <dd>Figma</dd> </dl> </section> <section class="career" id="career"> <h2>경력</h2> <table> <caption>Zeno Kim의 경력 요약</caption> <thead> <tr> <th scope="col">기간</th> <th scope="col">회사</th> <th scope="col">역할</th> <th scope="col">주요 업무</th> </tr> </thead> <tbody> <tr> <th scope="row">2024.03 – 현재</th> <td>스튜디오 파도</td> <td>프론트엔드 개발자</td> <td>사내 디자인 시스템 컴포넌트 구현, 접근성 개선</td> </tr> <tr> <th scope="row">2023.01 – 2024.02</th> <td>오늘의 기록</td> <td>주니어 개발자</td> <td>기록 서비스 웹 화면 개발, 반응형 전환</td> </tr> <tr> <th scope="row">2022.06 – 2022.12</th> <td>코드포올 부트캠프</td> <td>수료생</td> <td>팀 프로젝트 3건, 발표 우수상</td> </tr> </tbody> <tfoot> <tr> <td colspan="4">2022년부터 현재까지 총 3개 조직에서 경력을 쌓았습니다.</td> </tr> </tfoot> </table> </section> </main> <footer class="site-footer"> <p>&copy; 2026 Zeno Kim. 이 사이트는 학습용으로 제작되었습니다.</p> <nav aria-label="소셜 링크"> <ul> <li><a href="https://github.com/example" target="_blank" rel="noopener noreferrer">GitHub</a></li> <li><a href="https://www.linkedin.com/in/example" target="_blank" rel="noopener noreferrer">LinkedIn</a></li> <li><a href="https://blog.example.com" target="_blank" rel="noopener noreferrer">Blog</a></li> </ul> </nav> </footer> </body> </html>
<!-- web-practice/portfolio/projects.html --> <!doctype html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Zeno Kim — 프로젝트</title> </head> <body> <header class="site-header"> <a class="logo" href="index.html">Zeno Kim</a> <nav class="site-nav" aria-label="주 메뉴"> <ul> <li><a href="index.html">소개</a></li> <li><a href="projects.html" aria-current="page">프로젝트</a></li> <li><a href="contact.html">연락</a></li> </ul> </nav> </header> <main> <h1>프로젝트</h1> <p>직접 만들고 배운 것들을 모았습니다.</p> <div class="project-grid"> <article class="project-card" data-project-id="1"> <img src="images/project-01.svg" alt="오늘의 날씨 프로젝트 화면" width="1200" height="800" /> <h2>오늘의 날씨</h2> <p>위치 기반 날씨를 카드로 보여주는 웹앱입니다. 오프라인에서도 마지막 데이터를 보여줍니다.</p> <p>핵심 파일은 <code>weather-app/src/geo.js</code>입니다.</p> <pre><code>navigator.geolocation.getCurrentPosition((pos) => { fetchWeather(pos.coords.latitude, pos.coords.longitude); });</code></pre> <p>API는 <code>/api/weather?lat=1&amp;lon=2</code> 형태로 호출됩니다.</p> <blockquote cite="https://example.com/reviews/weather"> <p>실제 위치 기반 정보가 정확해서 매일 씁니다.</p> <footer>— 박서연, <cite>같은 팀 동료</cite></footer> </blockquote> <a href="https://example.com/weather" target="_blank" rel="noopener noreferrer">바로가기</a> </article> <article class="project-card" data-project-id="2"> <img src="images/project-02.svg" alt="독서 기록 bookshelf 프로젝트 화면" width="1200" height="800" /> <h2>독서 기록 bookshelf</h2> <p>읽은 책과 별점을 기록하고 통계를 보는 React 앱입니다.</p> <p>통계는 <code>booksReducer.js</code>의 <code>reduce</code> 호출로 계산합니다.</p> <pre><code>&lt;BookCard rating={5} /&gt;</code></pre> <blockquote cite="https://example.com/reviews/bookshelf"> <p>다 읽은 책을 한눈에 정리해 주니 독서 습관 관리가 쉬워졌습니다.</p> <footer>— 김도윤, <cite>베타 사용자</cite></footer> </blockquote> <a href="https://example.com/bookshelf" target="_blank" rel="noopener noreferrer">바로가기</a> </article> <article class="project-card" data-project-id="3"> <img src="images/project-03.svg" alt="메모 앱 notes 프로젝트 화면" width="1200" height="800" /> <h2>메모 앱 notes</h2> <p>브라우저 저장소만으로 동작하는 메모 앱입니다. 검색은 Worker가 담당합니다.</p> <p>검색 로직은 <code>search.worker.js</code>에 있습니다.</p> <blockquote cite="https://example.com/reviews/notes"> <p>메모가 몇백 개여도 검색이 즉시 됩니다.</p> <footer>— 이하은, <cite>베타 사용자</cite></footer> </blockquote> <a href="https://example.com/notes" target="_blank" rel="noopener noreferrer">바로가기</a> </article> <article class="project-card" data-project-id="4"> <img src="images/project-04.svg" alt="접근성 체크리스트 프로젝트 화면" width="1200" height="800" /> <h2>접근성 체크리스트</h2> <p>WCAG 항목을 하나씩 점검하는 정적 사이트입니다.</p> <p>항목마다 <code>role</code>과 <code>aria-*</code> 속성 예시를 보여줍니다.</p> <pre><code>&lt;button aria-pressed="false"&gt;저장됨&lt;/button&gt;</code></pre> <blockquote cite="https://example.com/reviews/a11y"> <p>사내 접근성 교육 자료로 그대로 썼습니다.</p> <footer>— 정민재, <cite>같은 팀 동료</cite></footer> </blockquote> <a href="https://example.com/a11y" target="_blank" rel="noopener noreferrer">바로가기</a> </article> <article class="project-card" data-project-id="5"> <img src="images/project-05.svg" alt="디자인 토큰 미리보기 프로젝트 화면" width="1200" height="800" /> <h2>디자인 토큰 미리보기</h2> <p>CSS 변수로 만든 색·간격 토큰을 한 화면에서 비교합니다.</p> <p>토큰은 <code>--color-primary</code>처럼 커스텀 속성으로 정의합니다.</p> <blockquote cite="https://example.com/reviews/tokens"> <p>디자인 시스템 문서로 참고하기 좋습니다.</p> <footer>— 오지훈, <cite>디자이너</cite></footer> </blockquote> <a href="https://example.com/tokens" target="_blank" rel="noopener noreferrer">바로가기</a> </article> <article class="project-card" data-project-id="6"> <img src="images/project-06.svg" alt="todo-cli 프로젝트 화면" width="1200" height="800" /> <h2>todo-cli</h2> <p>터미널에서 쓰는 할 일 관리 도구입니다. 파일에 저장하고 통계를 냅니다.</p> <p> 터미널에 <kbd>todo add "책 읽기"</kbd>를 입력하면 <samp>할 일이 추가되었습니다</samp>가 출력됩니다. </p> <blockquote cite="https://example.com/reviews/todo-cli"> <p>마우스 없이 할 일을 관리하니 더 빠릅니다.</p> <footer>— 최유나, <cite>베타 사용자</cite></footer> </blockquote> <a href="https://example.com/todo-cli" target="_blank" rel="noopener noreferrer">바로가기</a> </article> </div> </main> <footer class="site-footer"> <p>&copy; 2026 Zeno Kim. 이 사이트는 학습용으로 제작되었습니다.</p> <nav aria-label="소셜 링크"> <ul> <li><a href="https://github.com/example" target="_blank" rel="noopener noreferrer">GitHub</a></li> <li><a href="https://www.linkedin.com/in/example" target="_blank" rel="noopener noreferrer">LinkedIn</a></li> <li><a href="https://blog.example.com" target="_blank" rel="noopener noreferrer">Blog</a></li> </ul> </nav> </footer> </body> </html>
<!-- web-practice/portfolio/contact.html --> <!doctype html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Zeno Kim — 연락</title> </head> <body> <header class="site-header"> <a class="logo" href="index.html">Zeno Kim</a> <nav class="site-nav" aria-label="주 메뉴"> <ul> <li><a href="index.html">소개</a></li> <li><a href="projects.html">프로젝트</a></li> <li><a href="contact.html" aria-current="page">연락</a></li> </ul> </nav> </header> <main> <h1>연락</h1> <p>협업·채용 제안은 아래 폼으로 보내 주세요. 보통 2일 안에 답합니다.</p> <div class="contact-form" id="contact-form"> <form method="post" action="contact.html"> <fieldset> <legend>연락 정보 입력</legend> <div class="form-field"> <label for="name">이름</label> <input type="text" id="name" name="name" required /> </div> <div class="form-field"> <label for="email">이메일</label> <input type="email" id="email" name="email" required /> <p class="form-help">답장을 받을 주소를 적어 주세요.</p> </div> <div class="form-field"> <label for="inquiry-type">문의 유형</label> <select id="inquiry-type" name="inquiryType"> <option value="collab">협업 제안</option> <option value="hiring">채용 제안</option> <option value="etc" selected>기타</option> </select> </div> <div class="form-field"> <label for="message">메시지</label> <textarea id="message" name="message" minlength="10" required></textarea> <p class="form-help">프로젝트 내용이나 일정을 간단히 적어 주세요.</p> </div> <div class="form-field"> <label for="agree"> <input type="checkbox" id="agree" name="agree" required /> 개인정보 수집·이용에 동의합니다 </label> </div> <button type="submit">보내기</button> </fieldset> </form> </div> <aside class="faq"> <!-- modern_html: FAQ 아코디언 --> </aside> </main> <footer class="site-footer"> <p>&copy; 2026 Zeno Kim. 이 사이트는 학습용으로 제작되었습니다.</p> <nav aria-label="소셜 링크"> <ul> <li><a href="https://github.com/example" target="_blank" rel="noopener noreferrer">GitHub</a></li> <li><a href="https://www.linkedin.com/in/example" target="_blank" rel="noopener noreferrer">LinkedIn</a></li> <li><a href="https://blog.example.com" target="_blank" rel="noopener noreferrer">Blog</a></li> </ul> </nav> </footer> </body> </html>

3. 다음 과목 출발점 확인

css_fundamentals 01편은 이 세 파일을 그대로 이어받는다. 새로 만들 파일은 web-practice/portfolio/css/tokens.csscss/styles.css 두 개뿐이고, 각 HTML 파일의 headlink 태그를 추가하는 것이 첫 작업이다. 지금 만든 class·id는 손대지 않는다.

4. 확인

  • 시안(design-spec.md)의 섹션 순서와 지금 마크업의 섹션 순서가 일치한다
  • 위 세 코드 블록과 자신의 파일이 구조·클래스명 기준으로 같다(내용 문구는 원고를 그대로 옮겼는지만 대조)
  • css_fundamentals 01편에서 어떤 파일 경로에 link 태그를 추가할지 말할 수 있다

직접 해보기

design-spec.md의 “4. 레이아웃 스펙 — 프로젝트 카드” 절을 읽고, 지금 마크업의 .project-card 안에서 시안이 요구하는 순서(썸네일 → 제목 → 설명 → 태그 → 버튼)와 실제 순서가 같은지 확인해 보자.

정답 보기

지금 마크업은 썸네일(img) → 제목(h2) → 설명(p) → 코드 예시(p/pre, 카드에 따라 있음) → 인용구(blockquote) → 링크(a) 순서다. 시안이 요구하는 태그 리스트(칩)는 아직 없고, “자세히” 버튼도 modern_html에서 dialog로 구현되므로 지금은 대신 외부 링크로 대체했다. 두 가지 모두 뒤 과목에서 채워질 자리라는 점을 확인한다.

자주 하는 실수

증상원인고치는 법
css_fundamentals를 시작하니 class가 시안과 안 맞는다이 과목에서 임의로 class명을 다르게 지음이 편의 정본 코드에 나온 class명으로 지금 맞춰 둔다
link 태그를 이 과목에서 미리 추가했다CSS 파일이 없는데 head에 link만 넣어 404가 남css_fundamentals 01편에서 tokens.css를 만든 다음에 추가한다
세 파일의 헤더·푸터가 서로 다르다편마다 한 파일씩만 고치며 다른 파일에 반영을 빠뜨림지금 정본 코드와 세 파일을 나란히 비교해 헤더·푸터를 통일한다

확인 문제

문제 14지선다
css_fundamentals가 새로 만드는 파일로 옳은 것은?
문제 24지선다
지금 마크업에 미리 class를 지어 둔 이유는?
문제 34지선다
이 과목이 끝난 시점의 마크업과 시안의 관계로 옳은 것은?
문제 44지선다
프로젝트 카드의 '자세히' 버튼이 이 과목에서 외부 링크로 대체된 이유는?
문제 54지선다
css_fundamentals 01편을 시작하기 전에 확인해야 할 것은?

참고 자료

Last updated on