CSS 입문 10편 - 실전 프로젝트
※ 이 게시물은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

이제 진짜 웹사이트를 만들 시간!
지금까지 CSS의 기초부터 고급 기능까지 모두 배웠어요. 이제 이론은 충분하니 실전 프로젝트로 실력을 다져봅시다!
이번 글에서는 세 가지 완성도 높은 웹사이트를 처음부터 끝까지 만들어볼 거예요. 코드를 직접 따라 치면서 실력을 쌓으세요!
프로젝트 1: 개인 포트폴리오 사이트
HTML 구조
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>김개발 - 프론트엔드 개발자</title>
<link rel="stylesheet" href="portfolio.css">
</head>
<body>
<nav class="navbar">
<div class="logo">Kim Dev</div>
<ul class="nav-menu">
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<section class="hero">
<div class="hero-content">
<h1>안녕하세요, 김개발입니다</h1>
<p>사용자 경험을 최우선으로 생각하는 프론트엔드 개발자입니다.</p>
<a href="#projects" class="btn-primary">프로젝트 보기</a>
</div>
</section>
<section id="about" class="section">
<div class="container">
<h2>About Me</h2>
<div class="about-grid">
<div class="about-text">
<p>3년차 프론트엔드 개발자로, React와 Vue를 주로 사용합니다.</p>
<p>깔끔한 코드와 사용자 경험에 관심이 많습니다.</p>
</div>
<div class="about-image">
<img src="profile.jpg" alt="프로필">
</div>
</div>
</div>
</section>
<section id="projects" class="section section-gray">
<div class="container">
<h2>Projects</h2>
<div class="projects-grid">
<div class="project-card">
<img src="project1.jpg" alt="프로젝트 1">
<h3>전자상거래 플랫폼</h3>
<p>React와 Redux를 활용한 쇼핑몰 프로젝트</p>
<div class="project-tags">
<span class="tag">React</span>
<span class="tag">Redux</span>
<span class="tag">TypeScript</span>
</div>
</div>
<div class="project-card">
<img src="project2.jpg" alt="프로젝트 2">
<h3>업무 관리 대시보드</h3>
<p>Vue3와 Vuex를 활용한 프로젝트 관리 도구</p>
<div class="project-tags">
<span class="tag">Vue 3</span>
<span class="tag">Vuex</span>
<span class="tag">Sass</span>
</div>
</div>
<div class="project-card">
<img src="project3.jpg" alt="프로젝트 3">
<h3>날씨 알림 앱</h3>
<p>API 연동 및 위치 기반 날씨 정보 제공</p>
<div class="project-tags">
<span class="tag">JavaScript</span>
<span class="tag">API</span>
<span class="tag">CSS3</span>
</div>
</div>
</div>
</div>
</section>
<section id="contact" class="section">
<div class="container">
<h2>Contact</h2>
<div class="contact-info">
<p>이메일: kim@example.com</p>
<p>GitHub: github.com/kimdev</p>
<p>LinkedIn: linkedin.com/in/kimdev</p>
</div>
</div>
</section>
<footer>
<p>© 2025 Kim Dev. All rights reserved.</p>
</footer>
</body>
</html>
CSS (portfolio.css)
/* 변수 정의 */
:root {
--color-primary: #6366f1;
--color-text: #1f2937;
--color-text-light: #6b7280;
--color-bg: #ffffff;
--color-bg-light: #f9fafb;
--spacing: clamp(1rem, 3vw, 2rem);
--font-size-base: clamp(1rem, 2.5vw, 1.125rem);
--font-size-heading: clamp(2rem, 5vw, 3rem);
}
/* 리셋 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
color: var(--color-text);
line-height: 1.6;
font-size: var(--font-size-base);
}
/* 네비게이션 */
.navbar {
position: fixed;
top: 0;
width: 100%;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
z-index: 1000;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--color-primary);
}
.nav-menu {
display: flex;
gap: 2rem;
list-style: none;
}
.nav-menu a {
text-decoration: none;
color: var(--color-text);
font-weight: 500;
transition: color 0.3s;
}
.nav-menu a:hover {
color: var(--color-primary);
}
/* 히어로 섹션 */
.hero {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
text-align: center;
}
.hero-content h1 {
font-size: var(--font-size-heading);
margin-bottom: 1rem;
animation: fadeInUp 0.8s ease;
}
.hero-content p {
font-size: 1.25rem;
margin-bottom: 2rem;
opacity: 0.9;
animation: fadeInUp 0.8s ease 0.2s both;
}
.btn-primary {
display: inline-block;
padding: 1rem 2rem;
background: white;
color: var(--color-primary);
text-decoration: none;
border-radius: 50px;
font-weight: 600;
transition: all 0.3s;
animation: fadeInUp 0.8s ease 0.4s both;
}
.btn-primary:hover {
transform: translateY(-3px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 섹션 공통 */
.section {
padding: 5rem 2rem;
}
.section-gray {
background: var(--color-bg-light);
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.section h2 {
font-size: 2.5rem;
text-align: center;
margin-bottom: 3rem;
color: var(--color-text);
}
/* About 섹션 */
.about-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 3rem;
align-items: center;
}
.about-text p {
margin-bottom: 1rem;
color: var(--color-text-light);
}
.about-image img {
width: 100%;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
/* 프로젝트 그리드 */
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.project-card {
background: white;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
transition: transform 0.3s, box-shadow 0.3s;
}
.project-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 30px rgba(0,0,0,0.15);
}
.project-card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.project-card h3 {
padding: 1.5rem 1.5rem 0.5rem;
font-size: 1.25rem;
}
.project-card p {
padding: 0 1.5rem 1rem;
color: var(--color-text-light);
}
.project-tags {
display: flex;
gap: 0.5rem;
padding: 0 1.5rem 1.5rem;
flex-wrap: wrap;
}
.tag {
background: var(--color-bg-light);
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.875rem;
color: var(--color-primary);
}
/* 연락처 */
.contact-info {
text-align: center;
font-size: 1.125rem;
}
.contact-info p {
margin-bottom: 1rem;
}
/* 푸터 */
footer {
background: var(--color-text);
color: white;
text-align: center;
padding: 2rem;
}
/* 반응형 */
@media (max-width: 768px) {
.nav-menu {
display: none;
}
.about-grid {
grid-template-columns: 1fr;
}
.projects-grid {
grid-template-columns: 1fr;
}
.section {
padding: 3rem 1rem;
}
}
완성 모습:
고정 네비게이션, 그라디언트 히어로 섹션, 호버 효과가 있는 프로젝트 카드로 구성된 포트폴리오 사이트입니다
프로젝트 2: 제품 랜딩 페이지
핵심 CSS (간략 버전)
:root {
--gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--shadow-card: 0 10px 30px rgba(0,0,0,0.1);
}
/* 히어로 섹션 */
.landing-hero {
display: grid;
grid-template-columns: 1fr 1fr;
min-height: 100vh;
align-items: center;
gap: 4rem;
padding: 2rem;
}
.hero-text h1 {
font-size: clamp(2.5rem, 8vw, 5rem);
line-height: 1.1;
margin-bottom: 1.5rem;
}
.hero-image img {
width: 100%;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
/* 특징 카드 */
.features {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
padding: 5rem 2rem;
}
.feature-card {
text-align: center;
padding: 2rem;
border-radius: 20px;
background: white;
box-shadow: var(--shadow-card);
transition: transform 0.3s;
}
.feature-card:hover {
transform: translateY(-10px);
}
.feature-icon {
font-size: 3rem;
margin-bottom: 1rem;
}
/* CTA 버튼 */
.cta-section {
text-align: center;
padding: 5rem 2rem;
background: var(--gradient-primary);
color: white;
}
.cta-button {
display: inline-block;
padding: 1.25rem 3rem;
background: white;
color: #667eea;
font-size: 1.25rem;
font-weight: 600;
border-radius: 50px;
text-decoration: none;
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
transition: all 0.3s;
}
.cta-button:hover {
transform: scale(1.05);
box-shadow: 0 15px 35px rgba(0,0,0,0.3);
}
@media (max-width: 768px) {
.landing-hero {
grid-template-columns: 1fr;
}
.features {
grid-template-columns: 1fr;
}
}
완성 모습:
2단 그리드 히어로 섹션, 특징 카드, 그라디언트 CTA 버튼으로 구성된 제품 랜딩 페이지입니다

프로젝트 3: 대시보드 UI
HTML 구조
<div class="dashboard">
<aside class="sidebar">
<div class="sidebar-header">
<h2>Dashboard</h2>
</div>
<nav class="sidebar-nav">
<a href="#" class="nav-item active">
<span class="icon">📊</span>
<span>Overview</span>
</a>
<a href="#" class="nav-item">
<span class="icon">📈</span>
<span>Analytics</span>
</a>
<a href="#" class="nav-item">
<span class="icon">⚙️</span>
<span>Settings</span>
</a>
</nav>
</aside>
<main class="main-content">
<header class="topbar">
<h1>Overview</h1>
<div class="user-menu">
<img src="avatar.jpg" alt="User">
</div>
</header>
<div class="stats-grid">
<div class="stat-card">
<h3>Total Users</h3>
<p class="stat-value">12,456</p>
<span class="stat-change positive">+12.5%</span>
</div>
<div class="stat-card">
<h3>Revenue</h3>
<p class="stat-value">$45,231</p>
<span class="stat-change positive">+8.2%</span>
</div>
<div class="stat-card">
<h3>Orders</h3>
<p class="stat-value">1,234</p>
<span class="stat-change negative">-3.1%</span>
</div>
</div>
<div class="chart-container">
<h2>Sales Overview</h2>
<div class="chart-placeholder">
[차트가 여기에 표시됩니다]
</div>
</div>
</main>
</div>
CSS (dashboard.css)
:root {
--sidebar-width: 250px;
--topbar-height: 70px;
--color-primary: #6366f1;
--color-success: #10b981;
--color-danger: #ef4444;
--color-bg: #f9fafb;
--color-sidebar: #1e293b;
}
.dashboard {
display: grid;
grid-template-columns: var(--sidebar-width) 1fr;
min-height: 100vh;
}
/* 사이드바 */
.sidebar {
background: var(--color-sidebar);
color: white;
padding: 2rem 0;
}
.sidebar-header {
padding: 0 2rem;
margin-bottom: 2rem;
}
.sidebar-header h2 {
font-size: 1.5rem;
color: var(--color-primary);
}
.sidebar-nav {
display: flex;
flex-direction: column;
}
.nav-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem 2rem;
color: rgba(255,255,255,0.7);
text-decoration: none;
transition: all 0.3s;
}
.nav-item:hover {
background: rgba(255,255,255,0.1);
color: white;
}
.nav-item.active {
background: rgba(99, 102, 241, 0.2);
color: white;
border-left: 3px solid var(--color-primary);
}
.icon {
font-size: 1.25rem;
}
/* 메인 콘텐츠 */
.main-content {
background: var(--color-bg);
display: grid;
grid-template-rows: var(--topbar-height) 1fr;
}
/* 상단바 */
.topbar {
background: white;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.user-menu img {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
}
/* 통계 카드 */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
padding: 2rem;
}
.stat-card {
background: white;
padding: 1.5rem;
border-radius: 15px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.stat-card h3 {
font-size: 0.875rem;
color: #6b7280;
margin-bottom: 0.5rem;
}
.stat-value {
font-size: 2rem;
font-weight: bold;
margin-bottom: 0.5rem;
}
.stat-change {
font-size: 0.875rem;
font-weight: 600;
}
.stat-change.positive {
color: var(--color-success);
}
.stat-change.negative {
color: var(--color-danger);
}
/* 차트 */
.chart-container {
margin: 0 2rem 2rem;
background: white;
padding: 2rem;
border-radius: 15px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.chart-placeholder {
height: 300px;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-bg);
border-radius: 10px;
color: #6b7280;
}
/* 반응형 */
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
}
.sidebar {
display: none;
}
.stats-grid {
grid-template-columns: 1fr;
}
}
완성 모습:
고정 사이드바, 통계 카드, 차트 영역으로 구성된 관리자 대시보드 UI입니다
최종 체크리스트
프로젝트를 완성했다면 이것들을 확인하세요:
기능성
- 모든 링크 작동
- 반응형 동작 확인 (모바일, 태블릿, 데스크톱)
- 호버 효과 정상 작동
- 애니메이션 부드러움
성능
- 이미지 최적화 (WebP, 적절한 크기)
- CSS 파일 압축
- 불필요한 코드 제거
- 렌더링 성능 (transform, opacity 사용)
접근성
- 시맨틱 HTML 사용
- alt 속성 모든 이미지에 추가
- 키보드 탐색 가능
- 색상 대비 충분
호환성
- Chrome, Firefox, Safari에서 테스트
- 실제 모바일 기기에서 확인
다음 학습 방향
CSS를 넘어서
-
CSS 전처리기
- Sass/SCSS
- Less
-
CSS 프레임워크
- Tailwind CSS (추천!)
- Bootstrap
- Material UI
-
CSS-in-JS
- Styled Components
- Emotion
-
빌드 도구
- PostCSS
- CSS Modules
JavaScript 통합
<button class="toggle-button">테마 전환</button>
<script>
const button = document.querySelector('.toggle-button');
button.addEventListener('click', () => {
document.body.classList.toggle('dark');
});
</script>
지속적 학습
- Codepen: 다른 사람 코드 보기
- CSS Tricks: 최신 기법 배우기
- Frontend Mentor: 실전 프로젝트 연습
- Daily CSS: 매일 작은 프로젝트
마무리
CSS 독학 가이드 10편을 모두 완주하셨어요!
여러분은 이제:
- ✅ CSS 기초 완벽 이해
- ✅ Flexbox와 Grid로 자유로운 레이아웃
- ✅ 반응형 디자인 구현
- ✅ 애니메이션과 효과 추가
- ✅ 고급 선택자와 변수 활용
- ✅ 실전 프로젝트 제작
가장 중요한 것:
- 매일 조금씩 코드 치기
- 실제 프로젝트 만들어보기
- 다른 사람 코드 분석하기
- 트렌드 계속 따라가기
운영자 실전 노트
실제 프로젝트 진행하며 겪은 문제
- 실무 CSS 구조화 실패 → 하나의 CSS 파일에 5000줄. 기능별 분리(
reset.css,layout.css,components.css)했다 - 유지보수 전략 부재 → 6개월 후 내가 쓴 코드 이해 못함. 주석과 명확한 네이밍이 필수다
- 컴포넌트 재사용 안 됨 → 매번 비슷한 스타일 복붙. CSS 변수와 유틸리티 클래스로 재사용성 높였다
이 경험을 통해 알게 된 점
- CSS 아키텍처(SMACSS, ITCSS)를 초기 설계하면 확장이 쉽다
- 매일 작은 프로젝트를 만들면 실력이 기하급수적으로 는다
CSS는 끝이 없다. 계속 새로운 기능이 나오고, 디자인 트렌드도 바뀐다. 하지만 기초를 탄탄히 다졌으니 어떤 변화도 금방 따라잡을 수 있다.
여러분의 첫 프로젝트를 만들어보자. 완벽하지 않아도 괜찮다. 시작이 반이다.
시리즈 네비게이션
- 이전글: CSS 독학 가이드 - CSS 변수와 최신 기능
- 현재글: CSS 독학 가이드 - 실전 프로젝트
CSS 독학 가이드 시리즈를 모두 완주하셨습니다. 수고 많았어요!