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 독학 가이드 - CSS 변수와 최신 기능
- 현재글: CSS 독학 가이드 - 실전 프로젝트
CSS 독학 가이드 시리즈를 모두 완주하셨습니다. 수고 많았어요!
← 블로그 목록으로