본문으로 건너뛰기

모바일 먼저와 미디어 쿼리

HTML·CSS 목차화면 폭에 맞추기레슨 82 / 93

목차

미디어 쿼리(media query)는 '화면 폭이 640px 이상일 때'처럼 조건을 걸고, 조건이 맞을 때만 그 안의 규칙을 쓰게 하는 CSS입니다. 모바일 먼저(mobile first)는 기본 규칙을 좁은 화면에 맞춰 쓰고, 넓어지면 바뀔 선언만 @media (min-width: 640px) 조건 블록에 두는 차례입니다.

레시피 노트의 머리글은 휴대전화에서는 사이트 이름 아래에 내비게이션을 쌓는 편이 읽기 좋고, 넓은 화면에서는 한 줄 양 끝에 두는 편이 자리를 덜 씁니다. 한 CSS 파일로 두 모양을 내려면 '이 폭부터는 이렇게'라는 조건이 필요합니다. 이 레슨은 조건 블록이 언제 드는지, 기본 규칙과 어떻게 겨루는지, 그리고 모바일 먼저로 쓰는 하위 목표 셋을 봅니다.

그림 준비 중

1조건 블록 — 조건이 맞을 때만 안의 규칙이 든다

머리글을 모바일 먼저로 씁니다. 결과 화면 칸은 640px보다 좁아서, 예제마다 그릴 폭을 적어 그 폭으로 그린 뒤 칸에 맞게 줄여 보입니다.

<header class="site-header">
  <a href="index.html">
    레시피 노트
  </a>
  <nav>
    <a href="kimchi.html">
      김치볶음밥
    </a>
  </nav>
</header>
/* 1. 좁은 화면 기본 규칙 */
.site-header {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* 2. 넓어지면 바뀔 선언만 */
@media (min-width: 640px) {
  .site-header {
    flex-direction: row;
    justify-content:
      space-between;
  }
}
결과 화면폭 639px
잰 값개발자 도구에서 본 값
  • .site-header의 flex-directioncolumn
  • .site-header의 justify-contentnormal

@media 뒤 괄호가 조건이고, 그 뒤 중괄호가 조건 블록입니다. min-width: 640px은 '화면 폭(뷰포트 폭)이 640px 이상'입니다. 화면 폭 639px에서는 조건이 맞지 않아 조건 블록 안 규칙이 없는 것처럼 되고, 머리글은 기본 규칙대로 세로로 쌓였습니다. 조건이 맞을 때만 그 안의 규칙이 요소에 닿습니다(브라우저 규칙 4). 휴대전화에서 이 조건이 기기 화면 폭을 보려면 meta viewport의 뷰포트 줄이 있어야 합니다. 줄이 없으면 휴대전화도 980px 폭으로 배치해 min-width: 640px이 맞습니다.

2640은 든다 — 경계 폭

같은 코드를 1px 넓은 640px로 그립니다.

<header class="site-header">
  <a href="index.html">
    레시피 노트
  </a>
  <nav>
    <a href="kimchi.html">
      김치볶음밥
    </a>
  </nav>
</header>
.site-header {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

@media (min-width: 640px) {
  .site-header {
    flex-direction: row;
    justify-content:
      space-between;
  }
}
결과 화면폭 640px
잰 값개발자 도구에서 본 값
  • .site-header의 flex-directionrow
  • .site-header의 justify-contentspace-between

640px에서 머리글이 한 줄 양 끝으로 바뀌었습니다. min-은 '이상', max-는 '이하'라 경계 폭 자신이 듭니다 — min-width: 640px은 640에서 맞고 639에서 맞지 않습니다. 모양이 바뀌는 폭을 경계 폭(자료에 따라 브레이크포인트)이라고 부릅니다.

3기본 규칙과 조건 블록은 함께 든다

640px에서 머리글에 닿은 선언을 모아 봅니다.

선언어디에639px640px
display: flex기본 규칙듦듦
gap: 12px기본 규칙듦듦
flex-direction: column기본 규칙이김짐
flex-direction: row조건 블록닿지 않음이김
justify-content: space-between조건 블록닿지 않음듦

조건이 맞아도 기본 규칙은 그대로 듭니다. 그래서 조건 블록에는 display: flex를 다시 적지 않고 바뀔 선언만 둡니다. flex-direction처럼 두 곳에 같은 속성이 있으면, 선택자가 같으니 나중에 쓴 쪽이 이깁니다 — 조건 블록이 아래에 있어 row가 이겼습니다(브라우저 규칙 5). 조건 블록 안이라고 명시도가 높아지지는 않습니다.

4모바일 먼저 — 하위 목표 셋

1절 코드의 주석이 하위 목표입니다.

하위 목표할 일1절 코드
1. 좁은 화면 기본 규칙휴대전화 화면에 맞는 배치를 조건 없이 쓴다세로로 쌓는 .site-header
2. 넓어지면 바뀔 선언만 조건 블록에min-width 조건 블록을 기본 규칙 아래에 두고, 바뀌는 선언만 적는다row · space-between
3. 경계 폭에서 확인경계 폭과 1px 좁은 폭에서 둘 다 본다639 · 640

좁은 화면을 먼저 쓰는 까닭은 휴대전화에서 조건 블록을 하나도 읽지 않아도 되는 모양이 기본이 되기 때문입니다. 넓은 화면은 자리가 넉넉해 선언 몇 줄을 더해 바꾸기 쉽습니다. 경계 폭은 기기 이름이 아니라 내용을 보고 고릅니다. 창을 넓혀 가며 머리글이 한 줄에 무리 없이 들어가는 폭을 찾아 그 폭을 씁니다.

카드 격자의 열 수는 미디어 쿼리 없이도 바뀝니다. 들어가는 만큼 열 만들기의 auto-fill이 같은 폭에서 열 수를 따로 정합니다. 미디어 쿼리는 머리글처럼 폭에 따라 배치 방식을 바꿀 때 씁니다.

화면 폭이 아니라 그 요소를 담은 부모 상자의 폭을 조건으로 쓰는 컨테이너 쿼리(container query — @container)도 있습니다. 같은 카드가 넓은 칸과 좁은 칸에 함께 놓일 때 쓰며, 이 과목에서는 이름만 봅니다.

예제

후기 폼을 넓은 화면에서 한 줄로

레시피 후기 폼의 이름 칸과 단추를 좁은 화면에서는 세로로, 640px 이상에서는 한 줄로 놓습니다. 넓은 화면 쪽을 그립니다.

<form class="form-row">
  <label for="nick">이름</label>
  <input
    id="nick"
    name="nick"
  />
  <button type="submit">
    보내기
  </button>
</form>
/* 1. 좁은 화면 기본 규칙 */
.form-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* 2. 넓어지면 바뀔 선언만 */
@media (min-width: 640px) {
  .form-row {
    flex-direction: row;
    align-items: center;
  }
}
결과 화면폭 800px
잰 값개발자 도구에서 본 값
  • .form-row의 flex-directionrow
  • .form-row의 align-itemscenter
  • 800px은 640 이상이라 조건 블록이 들어 라벨 · 칸 · 단추가 한 줄입니다.
  • 3걸음 확인은 639px과 640px 두 폭에서 합니다. 639px에서는 flex-direction이 column이고 align-items는 처음 값 normal입니다.

자주 틀리는 곳

틀린 생각: min-width: 640px은 640을 빼고 641부터다.

2절 예제처럼 화면 폭 640px에서 flex-direction은 row입니다. 640px에서 이미 조건이 맞았습니다.

맞는 규칙: min-width는 '이상', max-width는 '이하'입니다. 경계 폭 자신이 듭니다.

틀린 생각: 조건 블록 안 규칙은 조건이 맞으면 늘 이긴다.

<header class="site-header">
  <a href="index.html">
    레시피 노트
  </a>
</header>
@media (min-width: 640px) {
  .site-header {
    flex-direction: row;
  }
}

.site-header {
  display: flex;
  flex-direction: column;
}
결과 화면폭 1280px
잰 값개발자 도구에서 본 값
  • .site-header의 flex-directioncolumn

1280px에서 조건은 맞았지만 머리글은 세로 그대로입니다. 조건 블록을 기본 규칙 위에 두어, 선택자가 같은 아래 기본 규칙이 나중에 쓴 쪽으로 이겼습니다.

맞는 규칙: 조건 블록은 명시도를 올리지 않고 차례로 겨룹니다. 조건 블록은 기본 규칙 아래에 둡니다.

틀린 생각: 조건의 숫자만 맞으면 단위는 없어도 된다.

<header class="site-header">
  <a href="index.html">
    레시피 노트
  </a>
</header>
.site-header {
  display: flex;
  flex-direction: column;
}

@media (min-width: 640) {
  .site-header {
    flex-direction: row;
  }
}
결과 화면폭 1280px
잰 값개발자 도구에서 본 값
  • .site-header의 flex-directioncolumn

1280px에서도 세로입니다. 640에 단위가 없어 브라우저가 조건을 알아듣지 못했고, 알아듣지 못한 조건은 어느 폭에서도 맞지 않습니다.

맞는 규칙: 조건의 폭에는 px 같은 단위를 붙입니다.

틀린 생각: 휴대전화 기종마다 그 폭의 조건 블록을 만든다.

휴대전화의 화면 폭은 기종마다 다릅니다(360 · 390 · 393 · 412px …). 'min-width: 393px은 iPhone 16용'처럼 만들면 기종이 나올 때마다 조건이 늘고, 390px 휴대전화는 393용 규칙을 받지 못합니다.

맞는 규칙: 경계 폭은 내용이 깨지기 시작하는 폭에서 고릅니다. 조건 블록은 몇 개 안으로 둡니다.

확인 문제

1. 예제 머리글 CSS에서 조건만 min-width: 800px로 바꿨습니다. 화면 폭 700px에서 머리글은 어떻게 보일까요? 보기 셋 가운데 고르세요.

<header class="site-header">
  <a href="index.html">
    레시피 노트
  </a>
  <nav>
    <a href="kimchi.html">
      김치볶음밥
    </a>
  </nav>
</header>
.site-header {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

@media (min-width: 800px) {
  .site-header {
    flex-direction: row;
    justify-content:
      space-between;
  }
}
힌트

화면 폭 700px이 조건 min-width: 800px을 채우는지부터 보세요.

정답

① — 700은 800 이상이 아니라 조건 블록이 들지 않고, 기본 규칙대로 세로로 쌓입니다.

결과 화면폭 700px
  • ②는 조건이 맞았을 때의 모양입니다. 800px부터 이렇게 바뀝니다.
  • ③은 조건 블록이 들어도 flex-direction만 바뀌고 justify-content는 안 든다고 본 것입니다. 조건이 맞으면 블록 안 선언이 함께 듭니다.

2. 레시피 노트의 카드 목록을 넓은 화면에서 두 열로 바꾸려고 합니다. 하위 목표 2의 조건 줄 ____ 자리를 채우세요 — 화면 폭 640px부터 두 열입니다.

/* 1. 좁은 화면 기본 규칙 */
.recipe-list {
  display: grid;
  gap: 16px;
}

/* 2. 넓어지면 바뀔 선언만 */
@media (____) {
  .recipe-list {
    grid-template-columns:
      1fr 1fr;
  }
}
힌트

'이상'을 나타내는 접두어와 단위까지 적습니다.

정답

min-width: 640px

  • @media (min-width: 640px) {⁠이 됩니다. 640px에서 맞고 639px에서 맞지 않습니다.
  • max-width: 640px이면 반대로 640px 이하에서 두 열이 됩니다.
  • min-width: 640처럼 단위를 빠뜨리면 어느 폭에서도 맞지 않습니다.

3. 플로우 카페 메뉴판의 메뉴 줄 CSS입니다. 화면 폭 640px과 641px에서 .menu의 flex-direction을 바르게 짝지은 것을 고르세요.

.menu {
  display: flex;
}

@media (max-width: 640px) {
  .menu {
    flex-direction: column;
  }
}
  • ① 640px column · 641px row
  • ② 640px row · 641px row
  • ③ 640px column · 641px column
힌트

max-가 '이하'인지 '미만'인지 정하고, 두 폭을 하나씩 조건에 넣어 보세요.

힌트 둘

조건이 맞지 않는 폭에서는 flex-direction을 적은 곳이 없습니다. 그때는 처음 값입니다.

정답

① — max-width: 640px은 '640px 이하'라 640에서 맞아 column, 641에서는 맞지 않아 처음 값 row입니다.

<ul class="menu">
  <li>커피 4000원</li>
  <li>라테 4500원</li>
</ul>
.menu {
  display: flex;
}

@media (max-width: 640px) {
  .menu {
    flex-direction: column;
  }
}
결과 화면폭 640px
잰 값개발자 도구에서 본 값
  • .menu의 flex-directioncolumn
  • ②는 경계 폭 640을 뺀다고 본 것입니다(경계를 빼는 생각).
  • ③은 조건 블록이 한 번 들면 넓어져도 남는다고 본 것입니다. 조건은 폭이 바뀔 때마다 다시 봅니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 1절의 머리글을 index.html과 style.css로 저장하고 link로 이어 엽니다(문서 뼈대의 body 안에 예제 HTML을 넣습니다). 개발자 도구 기기 모드에서 Dimensions: Responsive(크기: 반응형)를 고르고 너비 칸에 639와 640을 차례로 적어, 머리글이 바뀌는 폭을 봅니다. 이번에는 조건의 640을 641로 바꾸고 저장 · 새로고침한 뒤, 640에서 어떻게 될지 먼저 적고 맞춰 봅니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

HTML·CSS 목차로