css

clamp 함수 / 뷰포트 단위 / 최신 CSS 개발 패턴

내가 궁금했던 내용을 조사하고 GPT로 정리한 내용임

1. %와 vw의 차이

%는 부모 요소 기준

%는 부모 요소의 크기를 기준으로 계산된다.

.parent {
  width: 500px;
}
.child {
  width: 50%;
}

결과

부모 = 500px
50% = 250px

%는 부모 요소가 기준이다.


vw는 화면(Viewport) 기준

.child {
  width: 50vw;
}

브라우저 화면 너비가 1000px인 경우

50vw = 500px

부모 요소 크기와는 관계없이 현재 화면 크기를 기준으로 계산된다.


2. 실무에서 사용되는 경향

실무에서는 의외로 %를 훨씬 많이 사용한다.

레이아웃 내부 → %
화면 전체 높이 → dvh
화면 비례 크기 → vw
반응형 폰트 → vw 또는 clamp()
정사각형/원형 요소 → vmin

대표적인 사용 패턴은 다음과 같다.

첫 화면 높이
→ 100dvh

일반 컨텐츠 영역
→ 100%

화면 비례 크기
→ vw

반응형 폰트
→ vw 또는 clamp()

정사각형/원
→ vmin

3. 뷰포트 단위 정리

vw

현재 화면 너비의 1%

예를 들어 화면이

1200 × 800

이라면

1vw = 12px
10vw = 120px

화면 크기에 따라 동적으로 변경된다.


vh

현재 화면 높이의 1%

예를 들어 화면이

1200 × 800

이라면

1vh = 8px
10vh = 80px

마찬가지로 화면 크기에 따라 변경된다.


모바일에서 svh / lvh / dvh가 필요한 이유

모바일 브라우저는 주소창이 존재한다.

예를 들어 기기의 실제 높이가 800px이고 주소창이 100px이라고 가정하면

주소창 표시 중
→ 실제 보이는 화면 700px

주소창 숨김
→ 실제 보이는 화면 800px

이처럼 높이가 동적으로 변경된다.


svh (Small Viewport Height)

항상 가장 작은 높이를 사용한다.

100svh = 700px

주소창이 있든 없든 항상 700px이다.


lvh (Large Viewport Height)

항상 가장 큰 높이를 사용한다.

100lvh = 800px

주소창이 있든 없든 항상 800px이다.


dvh (Dynamic Viewport Height)

현재 실제 보이는 높이를 사용한다.

주소창 있음
100dvh = 700px

주소창 없음
100dvh = 800px

실시간으로 변경된다.

실무에서는 대부분 dvh를 사용한다.


동작 예시

초기 상태

기기 높이 = 800px
주소창 = 100px
실제 화면 = 700px

svh = 700
dvh = 700
lvh = 800

스크롤 후

기기 높이 = 800px
주소창 = 없음
실제 화면 = 800px

svh = 700
dvh = 800
lvh = 800

vmin

vwvh 중 더 작은 값을 사용한다.

예를 들어

1000 × 800

이면

vmin = 800 기준
.circle {
  width: 20vmin;
  height: 20vmin;
}

결과

20vmin = 160px

모바일

400 × 800

이면

vmin = 400 기준
20vmin = 80px

정사각형이나 원형 UI에서 자주 사용된다.


vmax

vwvh 중 더 큰 값을 사용한다.

1000 × 800
vmax = 1000 기준

특수한 디자인 요소나 대형 배경 텍스트에서 사용된다.

실무 사용 빈도는 매우 낮다.


4. clamp() 정리

구문

clamp(최소값, 선호값, 최대값)

예시

font-size: clamp(16px, 3vw, 32px);

의미

최소 16px
최대 32px

그 사이에서는 3vw를 기준으로 동적으로 변화

예를 들어 화면이

800 × 400

이면

1vw = 8px
3vw = 24px

결과

font-size = 24px

화면이 커지면

24px → 25px → 26px → ...

처럼 자연스럽게 증가한다.

최소 16px
최대 32px

범위를 벗어나지는 않는다.


clamp 등장 이전

과거에는 미디어 쿼리를 사용했다.

.title {
  font-size: 24px;
}

@media (min-width: 768px) {
  .title {
    font-size: 36px;
  }
}

@media (min-width: 1200px) {
  .title {
    font-size: 48px;
  }
}

문제점

1.코드가 길어짐
2.브레이크포인트 증가
3.크기가 계단식으로 변화

현재 방식

.title {
  font-size: clamp(24px, 3vw, 48px);
}

더 간결하고 부드럽게 변화한다.


5. 최신 CSS 개발 패턴

크기 조절

예전

font-size + @media

현재

font-size: clamp(...)

패턴

크기 조절
→ clamp()

사용 예

font-size
padding
margin
gap
width
height

화면 전체 높이

예전

height: 100vh;

현재

min-height: 100dvh;

패턴

전체 높이
→ dvh

가로 정렬

예전

float: left;

현재

display: flex;

패턴

가로 정렬
→ Flex

2차원 배치

예전

float
position
inline-block

현재

display: grid;

패턴

격자 배치
→ Grid

요소 간격

예전

margin-right: 20px;

현재

gap: 20px;

또는

gap: clamp(12px, 2vw, 32px);

패턴

요소 간격
→ gap

가운데 정렬

예전

position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

현재

display: flex;
justify-content: center;
align-items: center;

패턴

가운데 정렬
→ Flex

컨텐츠 폭 제한

예전

width: 1200px;

현재

width: 100%;
max-width: 1200px;
margin: 0 auto;

패턴

컨텐츠 영역
→ width:100% + max-width

반응형 레이아웃

현재

display: flex;
display: grid;
@media

패턴

배치
→ Flex/Grid

구조 변경
→ @media

컬러 관리

현재

:root {
  --primary-color: #1e88e5;
}

color: var(--primary-color);

패턴

색상 관리
→ CSS 변수

다크 모드

현재

@media (prefers-color-scheme: dark)

또는

[data-theme="dark"]

패턴

다크 모드
→ CSS 변수 + Theme

반응형 이미지

현재

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

패턴

이미지 반응형
→ max-width:100%

현업에서 가장 자주 보는 조합

.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

.hero {
  min-height: 100dvh;
}

.cards {
  display: grid;
  gap: clamp(16px, 2vw, 32px);
}

.title {
  font-size: clamp(24px, 4vw, 64px);
}

<header>
  <div class="container"></div> /* 안에 내용을 container에 정리함 이는 1200px까지 커지게 설정*/
</header>

<section class="hero"> /* 섹션은 해당 화면의 최대높이를 사용하도록 함 */
  <div class="container"></div>
</section>

요약하면 다음과 같다.

크기 조절      → clamp()
전체 높이      → dvh
가로 정렬      → Flex
격자 배치      → Grid
간격           → gap
반응형 구조    → @media
컨텐츠 폭 제한 → max-width
색상 관리      → CSS 변수
이미지         → max-width:100%