스타일 · CSS · 단위 · 반응형

CSS · 단위와 반응형

CSS? 로 크기를 적을 때는 "몇 px" 처럼 딱 못 박는 방법도 있고, "부모의 절반(50%)" 처럼 상황에 따라 늘었다 줄었다 하는 방법도 있습니다. 화면이 휴대폰부터 큰 모니터까지 제각각인 요즘은, 이 유연한 단위반응형 기법으로 한 벌의 HTML? 이 어디서나 보기 좋게 맞춰지도록 만듭니다.

절대 단위(px)는 "허리 75cm 정장"처럼 치수를 못 박은 옷이고, 상대 단위(%, em, vw)는 "몸에 맞춰 늘어나는 니트"입니다. 사람(화면)이 다양할수록 늘어나는 옷 한 벌이 훨씬 편하죠. 반응형은 그 위에 "더우면 반팔, 추우면 외투"처럼 상황별 규칙을 더한 것입니다.
검증 기준

이 문서의 단위·함수·미디어쿼리 동작은 모두 MDN CSS 레퍼런스 기준입니다. clamp(MIN, 선호, MAX) 는 정의상 max(MIN, min(선호, MAX)) 와 같고, 1rem 은 문서 루트(<html>)의 글자 크기(기본 16px)를 가리킵니다. 라이브 데모는 폭에 자연히 반응하는 것 위주로 두었어요 — 데모 화면(iframe)이 좁아 미디어쿼리의 폭 변화는 잘 안 보이므로, 미디어쿼리는 코드로 설명합니다.

1. 절대 단위 vs 상대 단위

무엇: 크기를 적는 단위는 크게 두 종류입니다. 화면이나 부모와 무관하게 고정절대 단위(대표: px)와, 무언가에 비례해서 변하는 상대 단위(%, em, rem, vw/vh, ch, fr)입니다.

단위기준(무엇에 비례하나)주로 쓰는 곳
px고정(절대). 1px = 화면의 1픽셀(논리 단위)테두리 두께, 1px 선처럼 늘면 곤란한 값
%부모 요소의 같은 속성 값(폭은 부모 폭의 %)폭·여백을 부모에 맞춰 늘리기
em그 요소의 글자 크기(font-size). font-size 자체에 쓰면 부모의 글자 크기버튼 안쪽 여백처럼 글자 크기에 비례시킬 때
rem루트(<html>)의 글자 크기. 기본 16px글자·간격의 전역 기준. 중첩돼도 안 흔들림
vw / vh뷰포트(보이는 화면) 폭/높이의 1%화면 가득 채우는 영역, 유동 글자
ch그 글꼴 0(영) 한 글자의 폭본문 한 줄 글자 수 제한(max-width: 60ch)
fr그리드 컨테이너의 남은 공간의 한 몫(fraction)Grid 칸 비율 나누기(1fr 2fr)
  • 언제 px: 테두리·구분선처럼 "절대 1px이어야" 하는 값. 늘어나면 안 되는 곳에만.
  • 언제 % / vw: 컨테이너나 화면 폭에 맞춰 같이 늘었다 줄어야 하는 폭·영역.
  • 언제 rem: 글자 크기와 간격의 전역 기준. 사용자가 브라우저 기본 글꼴을 키우면 같이 커져 접근성에 좋아요.
  • 언제 ch: 읽기 좋은 줄 길이(보통 45~75자) 제한. fr 은 Grid 전용 단위입니다.

em vs rem — 부모냐 루트냐

핵심 차이: em가장 가까운 부모의 글자 크기를 기준 삼아 중첩되면 누적됩니다(부모가 1.5em, 자식도 1.5em이면 2.25배). 반면 rem 은 언제나 루트 기준이라 아무리 깊이 중첩돼도 흔들리지 않아요. 아래 데모에서 직접 확인해 보세요 — 바깥 상자의 글자 크기를 바꾸면 em 글자만 따라 변합니다.

위 코드에서 .boxfont-size: 24px40px 으로 바꾸고 실행해 보세요. 1em 줄만 커지고 1rem 줄은 그대로입니다.

2. 함수형 크기 — min() · max() · clamp()

무엇: 여러 값 중에서 상황에 맞는 하나를 계산해서 고르는 CSS 함수입니다. 글자·폭을 화면에 따라 부드럽게(유동적으로) 변하게 할 때 핵심이에요.

함수고르는 값쓰임
min(a, b, …)가장 작은"이 폭을 넘기지 마라" 상한. width: min(100%, 600px)
max(a, b, …)가장 "이 아래로는 줄이지 마라" 하한. font-size: max(1rem, 2vw)
clamp(MIN, 선호, MAX)선호 값을 MIN~MAX 사이로 가둠유동 글자·폭. 너무 작지도 크지도 않게
/* clamp 는 정의상 다음과 같습니다 (MDN) */
clamp(MIN, 선호, MAX)  ≡  max(MIN, min(선호, MAX))

/* 예: 최소 16px, 선호는 화면 폭의 4%, 최대 32px */
h1 { font-size: clamp(16px, 4vw, 32px); }

/* 예: 본문 폭은 100% 까지 늘되 600px 을 넘기지 않음 */
.wrap { width: min(100%, 600px); }

아래 제목과 카드는 clamp() 로 만들었습니다. 데모 화면(또는 "크게 보기")의 폭을 좁혔다 넓히면 글자와 카드 폭이 구간 안에서 부드럽게 변합니다 — 미디어쿼리의 "딱딱 끊김"과 달리 연속적으로 변하는 게 특징이에요.

3. 미디어쿼리 — @media

무엇: "조건이 맞을 때만 이 스타일을 적용해라"라고 적는 규칙입니다. 화면 폭·방향·다크모드 같은 환경에 따라 다른 모습을 줄 수 있어요.

/* 폭이 768px 이상일 때만 */
@media (min-width: 768px) { .list { grid-template-columns: repeat(3, 1fr); } }

/* 폭이 480px 이하일 때만 */
@media (max-width: 480px) { .nav { display: none; } }

/* 화면 방향: 가로(landscape) / 세로(portrait) */
@media (orientation: landscape) { .banner { height: 40vh; } }

/* 사용자가 다크 테마를 선호할 때 */
@media (prefers-color-scheme: dark) { body { background: #0f141b; color: #e6eaf0; } }
  • min-width 는 "그 폭 이상", max-width 는 "그 폭 이하"에서 켜집니다.
  • orientationportrait(세로가 긺) 또는 landscape(가로가 긺) 두 값.
  • prefers-color-schemelight / dark — 사용자의 OS·브라우저 테마 설정을 읽어옵니다.
모바일 퍼스트 — 작게 먼저, min-width로 키운다

기본 스타일은 가장 좁은 화면(모바일) 기준으로 작게 짜 두고, @media (min-width: …) 로 폭이 넓어질 때 칸을 늘리는 식으로 더해 갑니다. 이렇게 하면 기본값이 단순해지고, 작은 화면에서 불필요한 무효화(override)가 줄어요.

/* 1) 기본(모바일): 한 줄에 1칸 */
.list { display: grid; grid-template-columns: 1fr; gap: 12px; }

/* 2) 넓어지면 키운다 */
@media (min-width: 600px)  { .list { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px)  { .list { grid-template-columns: repeat(3, 1fr); } }

4. 반응형 레이아웃 — 유연한 Flex / Grid

무엇: 미디어쿼리로 단계를 일일이 나누지 않고도, Grid의 auto-fit + minmax() 조합만으로 폭에 맞춰 칸 수가 자동으로 바뀌게 만들 수 있습니다.

.gallery {
  display: grid;
  /* 각 칸은 최소 180px, 남으면 똑같이 1fr 씩 나눠 채움.
     들어갈 만큼 칸을 자동으로 만들고(auto-fit), 폭이 좁아지면 줄을 바꿈 */
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
}
  • minmax(180px, 1fr) — 칸은 최소 180px, 자리가 남으면 1fr 로 같이 늘어남.
  • auto-fit — 한 줄에 들어갈 만큼 칸을 채우고, 빈 칸은 접어(collapse) 남은 칸을 늘림. (auto-fill 은 빈 칸을 그대로 둠.)
  • 그래서 화면을 좁히면 칸이 스스로 줄바꿈되고, 넓히면 한 줄에 더 많이 들어갑니다 — 미디어쿼리 없이도요.

아래 카드 갤러리의 폭을 바꾸면 한 줄에 들어가는 칸 수가 자동으로 달라집니다. ("크게 보기"로 열어 창을 넓혀 보세요.)

Flex로도 비슷하게 할 수 있어요: display:flex; flex-wrap:wrap; 에 각 아이템을 flex: 1 1 180px(최소 180px, 남으면 늘고, 넘치면 줄바꿈)로 두면 자동으로 줄이 바뀝니다.

5. 반응형 이미지와 뷰포트 meta

무엇: 이미지가 부모 폭을 넘어 삐져나오지 않게 하고, 휴대폰에서 화면이 축소돼 보이지 않도록 하는 두 가지 기본기입니다.

/* 이미지가 부모보다 커지지 않게, 비율은 유지 */
img {
  max-width: 100%;   /* 부모 폭을 넘지 않음 */
  height: auto;      /* 가로에 맞춰 세로를 비율대로 */
}

이 한 줄(max-width: 100%; height: auto;)이 반응형 이미지의 기본입니다. 아래 데모에서 박스 폭을 좁혀도 그림(여기선 색 블록)이 비율을 지키며 같이 줄어듭니다.

그리고 모든 반응형의 시작은 문서 <head> 안의 뷰포트 meta 한 줄입니다. 이게 없으면 휴대폰이 데스크톱 폭(보통 980px)인 척하며 화면을 통째로 축소해 버려, 미디어쿼리가 의도대로 작동하지 않아요.

<meta name="viewport" content="width=device-width, initial-scale=1" />
  • width=device-width — 페이지 폭을 기기 실제 화면 폭에 맞춤.
  • initial-scale=1 — 처음 확대 배율을 1배(축소 없음)로.

6. 다크모드 — prefers-color-scheme

무엇: 사용자가 OS나 브라우저를 어두운 테마로 쓰면, 그 설정을 읽어 색을 바꿔 주는 것입니다. 별도 버튼 없이 시스템 설정을 따라가는 가장 간단한 다크모드예요.

/* 1) 색을 변수로 빼 두고 */
:root { --bg: #ffffff; --fg: #1f2733; }

/* 2) 다크 선호일 때 변수만 바꿔 끼움 */
@media (prefers-color-scheme: dark) {
  :root { --bg: #0f141b; --fg: #e6eaf0; }
}

body { background: var(--bg); color: var(--fg); }

색을 CSS 변수로 모아 두면, 다크모드에서는 변수 값만 갈아 끼우면 되므로 규칙이 깔끔해집니다. (사용자가 직접 토글하는 버튼식 다크모드는 보통 <html data-theme="dark"> 같은 속성을 두고 그에 맞춰 변수를 바꾸는데, 이 사이트의 테마 버튼이 그 방식이에요.)

한눈에 — 단위 / 미디어쿼리 카탈로그

항목뜻 / 기준대표 예
px절대 단위(고정)border: 1px solid
%부모의 같은 속성에 비례width: 50%
em요소(또는 부모)의 글자 크기padding: 0.5em
rem루트 글자 크기(기본 16px)margin: 1rem
vw / vh뷰포트 폭/높이의 1%height: 100vh
ch글꼴 "0" 한 글자 폭max-width: 60ch
frGrid 남은 공간의 한 몫1fr 2fr
min(a, b)가장 작은 값(상한 만들기)min(100%, 600px)
max(a, b)가장 큰 값(하한 만들기)max(1rem, 2vw)
clamp(MIN, 선호, MAX)max(MIN, min(선호, MAX))clamp(16px, 4vw, 32px)
@media (min-width: n)폭 n 이상에서 적용모바일 퍼스트로 키울 때
@media (max-width: n)폭 n 이하에서 적용좁은 화면만 손볼 때
@media (orientation: …)portrait / landscape가로/세로 분기
@media (prefers-color-scheme: dark)다크 테마 선호시스템 따라 다크모드
repeat(auto-fit, minmax(n, 1fr))폭 따라 칸 수 자동카드 갤러리
실무 메모 — 모바일 퍼스트 · rem 기준

① 기본 스타일은 모바일(좁은 화면)부터 짜고 min-width 로 키워 가세요. 작은 화면이 가장 까다로우니 그것부터 단단하게. ② 글자·간격은 rem 을 기준으로 통일하면 전역 글꼴 크기 한 번으로 전체 스케일이 맞고, 사용자가 글자를 키워도 깨지지 않습니다. ③ 폭은 width: min(100%, 최대치), 글자는 clamp() 로 두면 미디어쿼리 없이도 대부분 유연하게 대응돼요. ④ 단계가 꼭 필요한 레이아웃 전환(1칸→3칸 등)에만 미디어쿼리를 쓰는 게 깔끔합니다.

다음 단계

  • 이 단위·반응형 개념을 유틸리티 클래스로 빠르게 쓰기 → Tailwind CSS
  • 반응형 컴포넌트를 미리 만들어진 UI로 → Shadcn UI