CSS

「실습」 주말 코딩 스터디 모집 페이지 만들기

실습 개요

  • 목표: 지금까지 배운 HTML 태그와 CSS를 한 페이지에 모두 모아 완성형 랜딩 페이지를 만든다.

  • 사용 범위: 시맨틱 태그 · 기본 선택자(태그/아이디/클래스) · 조합 선택자(후손/자식/인접 형제) · 색상과 배경 · 박스 모델 · 표/폼 꾸미기

  • 진행 방식: HTML 구조는 미리 제공된다. 여러분은 비어 있는 <style> 안에 CSS만 작성하면 된다.

이번 실습에서는 "주말 코딩 스터디" 회원을 모집하는 한 페이지짜리 랜딩 페이지를 완성한다. HTML 뼈대는 이미 짜여 있으니, 단계별 요구사항을 따라 CSS를 채워 가며 밋밋한 문서를 보기 좋은 페이지로 바꿔 보자.

페이지는 아래 5개 영역으로 구성된다.

┌──────────────────────────────────────────┐
│ <header>  제목 + 소개문구 + <nav> 메뉴      │   ← 머리말
├──────────────────────────────────────────┤
│ <main>                                     │
│   <section> 스터디 소개  (텍스트 + 이미지)  │
│   <section> 일정·회비    (표 table)         │
│   <section> 활동 내용    (목록 ul)          │
│   <section> 신청하기     (폼 form)          │
├──────────────────────────────────────────┤
│ <footer>  저작권 · 문의                     │   ← 꼬리말
└──────────────────────────────────────────┘

완성된 모습 (목표)

먼저 우리가 최종적으로 만들 결과물을 확인하자. 아래는 모든 단계를 끝낸 완성본이다. 실습 중간중간 "내가 지금 어디로 가고 있는지" 헷갈릴 때 이 화면을 기준으로 삼으면 된다.

🔗 완성본 새 탭에서 크게 보기

지금은 '목표 화면'만 눈에 담아 두세요

위 화면은 여러분이 직접 만들 결과물이다. 코드를 그대로 따라 적기보다, "머리말은 보라색 그라데이션, 본문은 흰 카드, 표는 선이 하나로 합쳐짐" 같은 전체 인상을 먼저 파악하고 단계로 들어가자. 각 단계의 정답 코드는 아래에서 하나씩 펼쳐 볼 수 있다.


0. 실습 준비

  1. 작업 폴더를 하나 새로 만든다. (예: study-signup)

  2. VS Code로 그 폴더를 열고, 그 안에 index.html 파일을 만든다.

  3. 아래 시작용 HTML을 통째로 복사해 index.html에 붙여 넣는다.

  4. Live Server로 띄워 두고, <style> 안을 채울 때마다 브라우저에서 결과를 확인하며 진행한다.

이 실습에서 HTML은 건드리지 않는다

HTML 구조는 이미 완성돼 있다. 우리가 채울 곳은 <head> 안 <style> ... </style> 사이뿐이다. (여유가 되면 <!-- TODO --> 주석 부분의 HTML을 직접 채워 봐도 좋다.)

시작용 HTML (그대로 복사하세요)

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>종합 실습 - 주말 코딩 스터디 모집</title>

    <!-- (선택) 웹 폰트: 제목용. 인터넷이 없으면 맑은 고딕으로 대체됩니다. -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Black+Han+Sans&display=swap" rel="stylesheet">

    <style>
        /* ===== 여기에 CSS를 작성하세요 ===== */


    </style>
</head>
<body>
    <!-- ===== 머리말 ===== -->
    <header>
        <h1 id="main-title">주말 코딩 스터디</h1>
        <p class="tagline">비전공자도 환영! 매주 토요일, 함께 성장해요 🚀</p>

        <nav>
            <ul class="menu">
                <li><a href="#about">소개</a></li>
                <li><a href="#schedule">일정·회비</a></li>
                <li><a href="#activities">활동</a></li>
                <li><a href="#apply">신청</a></li>
            </ul>
        </nav>
    </header>

    <!-- ===== 본문 ===== -->
    <main>
        <!-- 소개: 텍스트 태그 + 이미지 -->
        <section id="about">
            <h2>스터디 소개</h2>
            <p>매주 토요일 오후, 카페에 모여 웹 개발을 공부하는 모임입니다.</p>
            <p>
                <strong>혼자 공부하다 지치셨나요?</strong>
                함께라면 <em>꾸준함</em>이 쉬워집니다. HTML/CSS부터 차근차근 시작합니다.
            </p>
            <img class="intro-img" src="https://placehold.co/700x260?text=Weekend+Coding+Study"
                 alt="주말 코딩 스터디 모임 사진">
        </section>

        <!-- 일정/회비: 표 -->
        <section id="schedule">
            <h2>모집 일정 &amp; 회비</h2>
            <p>아래 일정을 확인하고 신청해 주세요.</p>
            <table>
                <thead>
                    <tr>
                        <th>구분</th>
                        <th>내용</th>
                    </tr>
                </thead>
                <tbody>
                    <tr><td>모집 인원</td><td>10명 (선착순)</td></tr>
                    <tr><td>모임 시간</td><td>매주 토요일 14:00 ~ 17:00</td></tr>
                    <tr><td>장소</td><td>강남역 스터디 카페</td></tr>
                    <!-- TODO(선택): '회비' 행을 직접 한 줄 추가해보세요 -->
                </tbody>
            </table>
        </section>

        <!-- 활동: 목록 -->
        <section id="activities">
            <h2>이런 걸 함께 해요</h2>
            <p>입문자 눈높이에 맞춘 커리큘럼으로 진행합니다.</p>
            <ul>
                <li>HTML/CSS로 나만의 웹 페이지 만들기</li>
                <li>매주 작은 미션 &amp; 코드 리뷰</li>
                <li>JavaScript 맛보기와 미니 프로젝트</li>
                <!-- TODO(선택): 활동 항목을 하나 더 추가해보세요 -->
            </ul>
        </section>

        <!-- 신청: 폼 -->
        <section id="apply">
            <h2>신청하기</h2>
            <p>아래 양식을 작성하면 신청이 완료됩니다.</p>
            <form>
                <div class="form-row">
                    <label for="name">이름 <span class="required">*</span></label>
                    <input class="input" type="text" id="name" name="name" placeholder="홍길동" required>
                </div>

                <div class="form-row">
                    <label for="email">이메일 <span class="required">*</span></label>
                    <input class="input" type="email" id="email" name="email" placeholder="example@email.com" required>
                </div>

                <div class="form-row">
                    <label>관심 분야</label><br>
                    <label><input type="radio" name="topic" value="web" checked> 웹 개발</label>
                    <label><input type="radio" name="topic" value="data"> 데이터 분석</label>
                    <label><input type="radio" name="topic" value="app"> 앱 개발</label>
                </div>

                <div class="form-row">
                    <label>참여 가능 시간</label><br>
                    <label><input type="checkbox" name="time" value="am"> 오전</label>
                    <label><input type="checkbox" name="time" value="pm" checked> 오후</label>
                </div>

                <div class="form-row">
                    <label for="msg">하고 싶은 말</label>
                    <textarea class="input" id="msg" name="msg" rows="4" placeholder="자유롭게 적어주세요"></textarea>
                </div>

                <div class="form-row">
                    <label><input type="checkbox" required> 개인정보 수집에 동의합니다 <span class="required">*</span></label>
                </div>

                <button type="submit" class="btn">신청서 제출</button>
            </form>
        </section>
    </main>

    <!-- ===== 꼬리말 ===== -->
    <footer>
        <p>&copy; 2026 주말 코딩 스터디 · 문의: study@example.com</p>
    </footer>
</body>
</html>

정답 코드는 숨겨져 있어요

각 단계의 "정답 코드 보기" 박스는 기본적으로 접혀 있다. 먼저 스스로 작성해 본 뒤, 막히거나 다 풀고 확인할 때 박스를 클릭해서 펼쳐 보자. 정답을 보기 전에 직접 끙끙대 보는 시간이 가장 많이 남는다.


1단계. 페이지 기본값 + 머리말(header) 꾸미기

가장 먼저 페이지 전체의 분위기를 정하는 기본값과, 맨 위 머리말(header) 을 꾸민다.

요구사항

  • [태그 선택자] body에 글꼴("맑은 고딕"), 글자색, 줄 간격(line-height), 은은한 배경색을 준다.

  • [색상/배경] header에 배경색(또는 그라데이션)을 주고 글자색을 흰색으로, 가운데 정렬한다.

  • [아이디 선택자] #main-title에 큰 글씨를 적용한다. (페이지에 하나뿐인 대표 제목)

  • [클래스 선택자] .tagline(소개 문구)을 살짝 작고 연하게 만든다.

왜 #main-title은 아이디고 .tagline은 클래스인가요?

대표 제목은 페이지에 딱 하나 → 아이디(#). 소개 문구·버튼·필수표시처럼 여러 번 재사용할 수 있는 스타일 → 클래스(.). 이 구분을 의식하며 작성하는 게 이번 실습의 핵심이다.

정답 코드 보기 (클릭해서 펼치기)

/* [CSS 기초] 전체 페이지 기본값 */
body {
    font-family: "맑은 고딕", "Malgun Gothic", sans-serif;
    color: #333;
    line-height: 1.7;
    margin: 0;
    background-color: #f5f5f7;
}

/* [시맨틱] header — 머리말 / [색상] 그라데이션 배경 */
header {
    background-image: linear-gradient(135deg, #7b1fa2, #5e35b1);
    color: white;
    text-align: center;
    padding: 48px 20px 0;
}

/* [아이디 선택자] 페이지에 하나뿐인 대표 제목 */
#main-title {
    font-family: "Black Han Sans", "맑은 고딕", sans-serif;
    font-size: 40px;
    margin: 0;
}

/* [클래스 선택자] 재사용 가능한 소개 문구 */
.tagline {
    font-size: 18px;
    opacity: 0.9;
}

2단계. 내비게이션 메뉴 (후손 · 자식 선택자)

머리말 안 메뉴(nav) 를 가로로 정렬하고 링크 모양을 다듬는다. 이번 단계의 목표는 후손 선택자와 자식 선택자의 차이를 손으로 익히는 것이다.

요구사항

  • [후손 선택자 nav a] nav 안의 모든 링크의 밑줄을 없애고 글자색을 바꾼다. (text-decoration: none)

  • [자식 선택자 .menu > li] .menu의 직계 <li>를 가로로 나열하고(display: inline-block) 목록 점(list-style)을 없앤다.

  • 메뉴 전체(.menu)의 기본 여백을 없애고 가운데 정렬한다.

완성 예시

nav a(후손)와 .menu > li(자식)의 차이

  • nav a → nav 안에 있는 모든 깊이의 <a>에 적용 (후손).

  • .menu > li → .menu 바로 한 단계 아래 <li>에만 적용 (직계 자식). 이 차이를 코드로 설명할 수 있어야 한다.

정답 코드 보기 (클릭해서 펼치기)

/* [시맨틱] nav — 메뉴 영역 */
nav {
    background-color: rgba(0, 0, 0, 0.15);
    margin-top: 24px;
}

.menu {
    margin: 0;
    padding: 0;
    text-align: center;
}

/* [자식 선택자 A > B] .menu의 '직계' li 만 가로 배치 */
.menu > li {
    display: inline-block;
    list-style: none;
}

/* [후손 선택자 A B] nav 안의 '모든' 링크 스타일 */
nav a {
    display: inline-block;
    padding: 14px 18px;
    color: white;
    text-decoration: none;   /* 링크 밑줄 제거 */
    font-weight: bold;
}

3단계. 본문 레이아웃 + 카드 (박스 모델)

본문(main)을 화면 가운데로 모으고, 각 section을 카드처럼 만든다. 제목(h2)과 요약문도 다듬는다.

요구사항

  • [박스 모델] main에 max-width: 760px; margin: 0 auto;를 줘 본문을 가운데 정렬한다.

  • [박스 모델] section에 padding · margin · border-radius · box-shadow를 줘 카드처럼 만든다. (배경은 흰색)

  • [태그 선택자] 모든 h2에 공통 색과 아래 테두리(border-bottom)를 준다.

  • [인접 형제 h2 + p] 각 제목 바로 다음 문단(요약문)만 회색 기울임으로 강조한다.

  • 소개 이미지(.intro-img)가 카드 너비에 꽉 차도록 width: 100%를 준다.

h2 + p는 '바로 다음' 하나만

인접 형제 선택자 h2 + p는 h2 직후에 붙어 있는 첫 <p> 하나에만 적용된다. 두 번째, 세 번째 문단은 회색이 되면 안 된다. 적용 결과를 브라우저에서 꼭 확인하자.

정답 코드 보기 (클릭해서 펼치기)

/* [태그 선택자] 페이지 안의 모든 h2 */
h2 {
    color: #5e35b1;
    border-bottom: 2px solid #ede7f6;   /* [박스모델] 아래 테두리 */
    padding-bottom: 8px;
}

/* [인접 형제 A + B] h2 '바로 다음' 첫 문단(요약문)만 */
h2 + p {
    color: #777;
    font-style: italic;
}

/* [시맨틱] main — 본문을 가운데로 */
main {
    max-width: 760px;
    margin: 0 auto;          /* 좌우 auto → 가운데 정렬 */
    padding: 20px;
}

/* [박스 모델] section을 카드처럼 */
section {
    background-color: white;
    padding: 24px;
    margin-bottom: 24px;
    border-radius: 12px;                        /* 둥근 모서리 */
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);  /* 그림자 */
}

/* 소개 이미지 */
.intro-img {
    width: 100%;
    border-radius: 8px;
    display: block;
    margin-top: 12px;
}

4단계. 일정·회비 표 꾸미기

schedule 영역의 표(table) 를 깔끔하게 다듬는다.

요구사항

  • [표 꾸미기] table에 width: 100%와 border-collapse: collapse를 준다.

  • th, td에 border와 padding을 줘 칸을 보기 좋게 만든다.

  • 머리 행(thead th)에 배경색을 줘 본문과 구분한다.

완성 예시

구분

내용

모집 인원

10명 (선착순)

모임 시간

매주 토요일 14:00 ~ 17:00

장소

강남역 스터디 카페

border-collapse: collapse가 없으면?

이 속성이 없으면 셀마다 테두리가 따로 그려져 선이 이중으로 보인다. collapse는 맞닿은 셀 선을 하나로 합쳐 준다.

정답 코드 보기 (클릭해서 펼치기)

/* [표 꾸미기] 일정/회비 표 */
table {
    width: 100%;
    border-collapse: collapse;   /* 셀 사이 이중선을 하나로 합침 */
}
th, td {
    border: 1px solid #ddd;
    padding: 10px 12px;
    text-align: center;
}
thead th {
    background-color: #ede7f6;    /* 머리 행 배경 */
    color: #5e35b1;
}

5단계. 신청 폼 + 버튼 꾸미기

apply 영역의 폼(form) 입력칸과 제출 버튼을 다듬는다. 이번 단계의 핵심은 글자 입력칸에만 스타일을 주는 것이다.

요구사항

  • [클래스 선택자] 글자 입력칸에만 붙은 .input(이름·이메일·하고 싶은 말)에 width: 100% · padding · border를 준다.

  • .input에 box-sizing: border-box를 줘 입력칸이 칸을 넘치지 않게 한다.

  • [클래스 선택자] .btn(제출 버튼)에 배경색 · 글자색 · 둥근 모서리 · cursor: pointer를 준다.

  • [클래스 선택자] .required(필수 표시 *)를 빨간색으로 만든다.

라디오·체크박스는 건드리지 않는다

.input 클래스는 글자 입력칸(text/email/textarea)에만 붙어 있다. 라디오·체크박스에는 .input이 없으므로 width: 100%의 영향을 받지 않는다. 선택자를 클래스로 좁힌 덕분이다.

입력칸이 오른쪽으로 넘쳐요

width: 100%에 padding까지 더해지면 칸을 넘친다. box-sizing: border-box;를 주면 padding이 너비 안에 포함돼 넘침이 사라진다. (1단계 박스 모델에서 배운 내용)

정답 코드 보기 (클릭해서 펼치기)

/* [폼 꾸미기] 신청 폼 */
.form-row { margin-bottom: 16px; }
label { display: inline-block; font-weight: bold; margin-bottom: 4px; }

/* [클래스 선택자] 글자 입력칸(.input)만 넓힘
   💬 라디오·체크박스엔 .input이 없어서 영향 없음 */
.input {
    width: 100%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 6px;
    box-sizing: border-box;   /* padding을 width 안에 포함 → 넘침 방지 */
    font-family: inherit;     /* 본문과 같은 글꼴 */
}

/* 제출 버튼 */
.btn {
    background-color: #5e35b1;
    color: white;
    border: none;
    padding: 12px 28px;
    border-radius: 999px;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
}

/* 필수 표시(*) — 클래스 재사용 */
.required { color: crimson; }

/* [시맨틱] footer — 꼬리말 */
footer {
    text-align: center;
    color: #999;
    padding: 24px;
    font-size: 14px;
}

전체 완성 코드

모든 단계를 합친 최종 <style>이다. 먼저 스스로 끝까지 만들어 본 뒤 펼쳐서 내 코드와 비교해 보자.

전체 정답 <style> 보기 (클릭해서 펼치기)

/* ===== [CSS 기초] 전체 페이지 기본값 ===== */
body {
    font-family: "맑은 고딕", "Malgun Gothic", sans-serif;
    color: #333;
    line-height: 1.7;
    margin: 0;
    background-color: #f5f5f7;
}

/* [태그 선택자] 모든 h2 */
h2 {
    color: #5e35b1;
    border-bottom: 2px solid #ede7f6;
    padding-bottom: 8px;
}
/* [인접 형제] h2 바로 다음 요약문 */
h2 + p {
    color: #777;
    font-style: italic;
}

/* ===== [시맨틱] header ===== */
header {
    background-image: linear-gradient(135deg, #7b1fa2, #5e35b1);
    color: white;
    text-align: center;
    padding: 48px 20px 0;
}
#main-title {                                   /* [아이디] */
    font-family: "Black Han Sans", "맑은 고딕", sans-serif;
    font-size: 40px;
    margin: 0;
}
.tagline {                                      /* [클래스] */
    font-size: 18px;
    opacity: 0.9;
}

/* ===== [시맨틱] nav / [조합 선택자] ===== */
nav {
    background-color: rgba(0, 0, 0, 0.15);
    margin-top: 24px;
}
.menu {
    margin: 0;
    padding: 0;
    text-align: center;
}
.menu > li {                                    /* [자식 선택자] */
    display: inline-block;
    list-style: none;
}
nav a {                                         /* [후손 선택자] */
    display: inline-block;
    padding: 14px 18px;
    color: white;
    text-decoration: none;
    font-weight: bold;
}

/* ===== [시맨틱] main / section ===== */
main {
    max-width: 760px;
    margin: 0 auto;
    padding: 20px;
}
section {                                       /* [박스 모델] 카드 */
    background-color: white;
    padding: 24px;
    margin-bottom: 24px;
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.intro-img {
    width: 100%;
    border-radius: 8px;
    display: block;
    margin-top: 12px;
}

/* ===== [표 꾸미기] ===== */
table {
    width: 100%;
    border-collapse: collapse;
}
th, td {
    border: 1px solid #ddd;
    padding: 10px 12px;
    text-align: center;
}
thead th {
    background-color: #ede7f6;
    color: #5e35b1;
}

/* ===== [폼 꾸미기] ===== */
.form-row { margin-bottom: 16px; }
label { display: inline-block; font-weight: bold; margin-bottom: 4px; }
.input {                                        /* [클래스] 글자 입력칸만 */
    width: 100%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 6px;
    box-sizing: border-box;
    font-family: inherit;
}
.btn {
    background-color: #5e35b1;
    color: white;
    border: none;
    padding: 12px 28px;
    border-radius: 999px;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
}
.required { color: crimson; }

/* ===== [시맨틱] footer ===== */
footer {
    text-align: center;
    color: #999;
    padding: 24px;
    font-size: 14px;
}

도전 과제

여유가 있다면 아래를 추가해 본다. 모두 지금까지 배운 선택자로 가능하다.

  • [가상 클래스] nav a:hover로 마우스를 올린 메뉴의 색을 바꿔 본다.

  • [가상 클래스 :nth-child] tbody tr:nth-child(2n)로 표의 짝수 줄에 배경색을 줘 얼룩말 무늬를 만든다.

  • [가상 클래스] .btn:hover에 색·그림자를 더해 버튼이 눌리는 느낌을 만든다.

  • 시작용 HTML의 <!-- TODO --> 부분(표의 '회비' 행, 활동 항목 하나)을 직접 채운다.


제출 / 점검 체크리스트

완성했다면 아래를 스스로 점검한다.

  • header → nav → main(section 4개) → footer 구조가 그대로 살아 있고, 각 영역이 의도대로 꾸며졌다.

  • 메뉴 링크를 누르면 해당 section으로 스크롤 이동한다. (href="#id" ↔ id)

  • nav a(후손)와 .menu > li(자식)의 차이를 코드로 설명할 수 있다.

  • 각 section 제목 바로 다음 문단만 회색 기울임이 되었다. (h2 + p)

  • 표의 선이 깔끔하게 하나로 합쳐졌다. (border-collapse)

  • 폼 입력칸이 카드를 넘치지 않는다. (box-sizing: border-box)

  • 라디오·체크박스는 width: 100%의 영향을 받지 않았다. (.input 클래스로 범위를 좁힘)

  • 이미지에 의미 있는 alt가 있다.

마지막 수정 2026년 10월 22일