CSS 입문 6편 - 반응형 웹 만들기

(수정: ) learning by Seven Fingers Studio 20분
CSS반응형미디어쿼리모바일퍼스트RWD

css guide 06 responsive

반응형 디자인이 필수인 이유

2025년 현재, 웹사이트 방문자의 70% 이상이 모바일로 접속해요. 데스크톱에서만 잘 보이는 웹사이트는 절반 이상의 사용자를 잃는 거죠.

반응형 디자인(Responsive Web Design)은 하나의 HTML로 모든 기기에 대응하는 기술이에요. 모바일 앱 따로, 웹사이트 따로 만들 필요 없이 CSS만으로 해결합니다!

제가 처음 만든 웹사이트는 데스크톱에서만 확인해서 모바일에서 완전 망가진 걸 나중에 알았어요. 지금은 항상 모바일부터 확인합니다.

뷰포트 메타 태그 (필수!)

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

설명:

viewport 메타 태그가 없으면: 모바일에서 데스크톱 화면이 축소되어 표시됨

viewport 메타 태그가 있으면: 기기 너비에 맞춰 적절하게 표시됨

이게 없으면 모바일에서 데스크톱 화면이 축소되어 보여요. 모든 웹사이트에 필수!

  • width=device-width: 기기 너비에 맞춤
  • initial-scale=1.0: 초기 확대 배율 1배

미디어 쿼리 기본

특정 화면 크기에서 다른 CSS를 적용해요.

/* 기본 스타일 (모든 화면) */
.container {
  padding: 20px;
}

/* 768px 이하 (태블릿, 모바일) */
@media (max-width: 768px) {
  .container {
    padding: 10px;
  }
}

주요 브레이크포인트

/* 모바일 (0~480px) */
@media (max-width: 480px) {
  /* 스타일 */
}

/* 태블릿 (481~768px) */
@media (min-width: 481px) and (max-width: 768px) {
  /* 스타일 */
}

/* 데스크톱 (769px~) */
@media (min-width: 769px) {
  /* 스타일 */
}

/* 대형 데스크톱 (1200px~) */
@media (min-width: 1200px) {
  /* 스타일 */
}

실무에서 자주 쓰는 브레이크포인트:

  • 480px: 모바일
  • 768px: 태블릿
  • 1024px: 작은 데스크톱
  • 1280px: 일반 데스크톱

Mobile First vs Desktop First

Desktop First (예전 방식)

/* 기본: 데스크톱 */
.container {
  width: 1200px;
}

/* 작은 화면에서 수정 */
@media (max-width: 768px) {
  .container {
    width: 100%;
  }
}

Mobile First (현대적 방식) ⭐ 추천

/* 기본: 모바일 */
.container {
  width: 100%;
  padding: 10px;
}

/* 큰 화면에서 확장 */
@media (min-width: 768px) {
  .container {
    width: 750px;
    padding: 20px;
  }
}

@media (min-width: 1024px) {
  .container {
    width: 1000px;
  }
}

Mobile First가 좋은 이유:

  • 모바일이 기본이 되는 시대
  • 성능 최적화 (작은 화면부터 시작)
  • 점진적 향상 (Progressive Enhancement)

유동 레이아웃

고정 크기 → 상대 크기

/* ❌ 나쁜 예 (고정 크기) */
.container {
  width: 1200px;
}

/* ✅ 좋은 예 (상대 크기) */
.container {
  width: 90%;
  max-width: 1200px;
}

% vs vw/vh

/* 부모 기준 */
.box {
  width: 50%;  /* 부모의 50% */
}

/* 뷰포트 기준 */
.hero {
  width: 100vw;   /* 뷰포트 너비의 100% */
  height: 100vh;  /* 뷰포트 높이의 100% */
}

언제 뭘 쓸까?

  • %: 일반적인 레이아웃
  • vw/vh: 전체 화면 섹션 (히어로 이미지 등)

반응형 이미지

1. 기본 방법

img {
  max-width: 100%;
  height: auto;
}

이것만 해도 이미지가 컨테이너를 벗어나지 않아요!

2. srcset 속성

<img
  src="image-small.jpg"
  srcset="image-small.jpg 480w,
          image-medium.jpg 768w,
          image-large.jpg 1200w"
  sizes="(max-width: 480px) 100vw,
         (max-width: 768px) 50vw,
         33vw"
  alt="반응형 이미지"
>

브라우저가 자동으로 적절한 크기 선택!

3. picture 태그

<picture>
  <source media="(max-width: 480px)" srcset="mobile.jpg">
  <source media="(max-width: 768px)" srcset="tablet.jpg">
  <img src="desktop.jpg" alt="반응형 이미지">
</picture>

화면 크기별로 완전히 다른 이미지 사용 가능!

css guide 06 responsive

실전 예제 1: 반응형 네비게이션

<nav class="navbar">
  <div class="logo">MyLogo</div>
  <button class="menu-toggle">☰</button>
  <ul class="menu">
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  background: #333;
  color: white;
}

.menu {
  display: flex;
  gap: 2rem;
  list-style: none;
}

.menu-toggle {
  display: none;  /* 데스크톱에서 숨김 */
  background: none;
  border: none;
  color: white;
  font-size: 1.5rem;
  cursor: pointer;
}

/* 모바일 */
@media (max-width: 768px) {
  .menu {
    display: none;  /* 기본 숨김 */
    position: absolute;
    top: 60px;
    left: 0;
    right: 0;
    flex-direction: column;
    background: #333;
    padding: 1rem;
  }

  .menu.active {
    display: flex;  /* 토글 시 표시 */
  }

  .menu-toggle {
    display: block;  /* 햄버거 버튼 표시 */
  }
}

JavaScript로 .active 클래스만 토글하면 됩니다!

실전 예제 2: 반응형 그리드

<div class="grid">
  <div class="card">Card 1</div>
  <div class="card">Card 2</div>
  <div class="card">Card 3</div>
  <div class="card">Card 4</div>
</div>
.grid {
  display: grid;
  gap: 20px;
  padding: 20px;
}

/* 모바일: 1열 */
@media (max-width: 480px) {
  .grid {
    grid-template-columns: 1fr;
  }
}

/* 태블릿: 2열 */
@media (min-width: 481px) and (max-width: 768px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* 데스크톱: 3열 */
@media (min-width: 769px) and (max-width: 1024px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* 대형 데스크톱: 4열 */
@media (min-width: 1025px) {
  .grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

미디어 쿼리 없는 자동 반응형:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

이게 훨씬 간단하죠!

실전 예제 3: 반응형 타이포그래피

/* 기본 (모바일) */
body {
  font-size: 14px;
}

h1 { font-size: 1.8rem; }
h2 { font-size: 1.5rem; }
p { line-height: 1.5; }

/* 태블릿 */
@media (min-width: 768px) {
  body {
    font-size: 16px;
  }

  h1 { font-size: 2.2rem; }
  h2 { font-size: 1.8rem; }
  p { line-height: 1.6; }
}

/* 데스크톱 */
@media (min-width: 1024px) {
  body {
    font-size: 18px;
  }

  h1 { font-size: 2.5rem; }
  h2 { font-size: 2rem; }
  p { line-height: 1.7; }
}

clamp() 함수로 유동 타이포그래피:

h1 {
  font-size: clamp(1.8rem, 5vw, 2.5rem);
  /* 최소 1.8rem, 이상적 5vw, 최대 2.5rem */
}

화면 크기에 따라 자동으로 조정!

컨테이너 쿼리 (최신 기능)

요소의 크기에 따라 스타일 변경 (뷰포트가 아닌!)

.sidebar {
  container-type: inline-size;
}

.card {
  padding: 1rem;
}

@container (min-width: 400px) {
  .card {
    padding: 2rem;
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

사이드바가 넓어지면 카드 레이아웃이 바뀝니다! (2024년부터 주요 브라우저 지원)

숨기기/보이기 패턴

/* 모바일에서만 보임 */
.mobile-only {
  display: block;
}

@media (min-width: 768px) {
  .mobile-only {
    display: none;
  }
}

/* 데스크톱에서만 보임 */
.desktop-only {
  display: none;
}

@media (min-width: 768px) {
  .desktop-only {
    display: block;
  }
}

터치 기기 감지

/* 터치 기기 (모바일, 태블릿) */
@media (hover: none) and (pointer: coarse) {
  .button {
    min-height: 44px;  /* 터치하기 쉽게 크게 */
    min-width: 44px;
  }
}

/* 마우스 기기 (데스크톱) */
@media (hover: hover) and (pointer: fine) {
  .button:hover {
    background: #0056b3;
  }
}

다크 모드 대응

/* 라이트 모드 (기본) */
body {
  background: #fff;
  color: #333;
}

/* 다크 모드 */
@media (prefers-color-scheme: dark) {
  body {
    background: #1a1a1a;
    color: #e0e0e0;
  }
}

사용자의 시스템 설정을 자동으로 따라갑니다!

성능 최적화 팁

1. 불필요한 미디어 쿼리 줄이기

/* ❌ 나쁜 예 */
@media (max-width: 768px) {
  .box { padding: 10px; }
}
@media (max-width: 768px) {
  .card { margin: 5px; }
}

/* ✅ 좋은 예 */
@media (max-width: 768px) {
  .box { padding: 10px; }
  .card { margin: 5px; }
}

2. min-width 우선 사용 (Mobile First)

/* 기본: 모바일 */
.container { padding: 10px; }

/* 확장: 큰 화면 */
@media (min-width: 768px) {
  .container { padding: 20px; }
}

3. CSS 변수 활용

:root {
  --spacing: 10px;
  --container-width: 100%;
}

@media (min-width: 768px) {
  :root {
    --spacing: 20px;
    --container-width: 750px;
  }
}

.container {
  padding: var(--spacing);
  max-width: var(--container-width);
}

반응형 체크리스트

  • viewport 메타 태그 추가
  • 이미지에 max-width: 100%
  • 고정 크기 대신 상대 크기 사용
  • Mobile First 접근
  • 터치 타겟 최소 44x44px
  • 가로 스크롤 방지
  • 실제 기기에서 테스트
  • 개발자 도구로 여러 화면 크기 확인

디버깅 팁

Chrome DevTools

  1. F12 → 기기 툴바 토글 (Ctrl+Shift+M)
  2. 상단에서 기기 선택 (iPhone, iPad 등)
  3. 커스텀 크기도 입력 가능

반응형 테스트 사이트

  • Responsive Design Checker
  • BrowserStack (실제 기기 테스트)
  • Mobile-Friendly Test (Google)

운영자 실전 노트

실제 프로젝트 진행하며 겪은 문제

  • 미디어쿼리 순서 실수 → max-width를 큰 순서대로 안 씀. 768px 이후에 1024px 쓰면 override됨
  • 모바일 퍼스트 미적용 → 데스크톱 먼저 작성 후 모바일 대응. 처음부터 Mobile First가 효율적이다
  • 고정 단위 사용 → px로 고정하니 유연하지 못함. rem, %, vw 등 상대 단위 사용해야 한다

이 경험을 통해 알게 된 점

  • 브레이크포인트 768px, 1024px가 표준. 디바이스 실사용 통계 기반이다
  • 개발 시 브라우저 창을 반만 열어두면 자연스럽게 반응형으로 만들게 된다

다음 단계

다음 글에서는 애니메이션과 전환 효과를 배운다. 움직임을 추가하면 사용자 경험이 훨씬 좋아진다.

실습 과제:

  • 네비게이션 바를 모바일에서 햄버거 메뉴로 바꿔보기
  • 3열 그리드를 모바일에서 1열로 변경하기
  • 타이포그래피를 화면 크기별로 다르게 설정하기
  • 실제 휴대폰에서 웹사이트 확인해보기

Chrome DevTools의 기기 에뮬레이션을 활용하되, 최종적으로는 실제 기기에서 테스트하자.

시리즈 네비게이션

← 블로그 목록으로