본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Frontend

CSS 점진적 향상: 폴백과 피처 쿼리

작성 2026. 10. 21.추가
목차13개 항목
출처와 참고

Rachel Andrew의 「CSS 그리드로 미지원 브라우저 지원하기」(2018.01)·「CSS 그리드 레이아웃을 지금 사용해도 정말 괜찮을까」(2017.11)와 Daniel Tonon의 「IE에서 CSS 그리드 사용하기」 시리즈(2018~2020, 웹액츄얼리 번역)를 바탕으로 재구성한 노트다. 지원 등급은 Yahoo의 「Graded Browser Support」와 Filament Group의 「Grade components, not browsers」(2013)를 바탕으로 더했다.

점진적 향상이란

점진적 향상(Progressive Enhancement)은 모든 브라우저에 쓸 만한 기본 경험을 주고, 새 기능을 지원하는 브라우저에는 더 나은 경험을 얹는 방식이다. 출발점은 "지원"의 뜻을 정하는 것이다.

"지원"의 뜻결과
모든 브라우저에서 똑같이 보인다새 기능은 가장 오래된 대상 브라우저가 지원할 때까지 못 쓴다
모든 브라우저에서 콘텐츠를 무리 없이 쓸 수 있다새 기능을 지금 쓰고, 옛 브라우저에는 단순한 레이아웃을 준다

모든 브라우저에서 똑같아야 한다면 그 기능을 쓰지 않는다. 새 기능은 이전에 불가능했던 일을 하려고 쓰는 것이지, 옛 디자인을 똑같이 재현하려고 쓰는 것이 아니다.

CSS 그리드·플렉스박스는 이제 모든 주요 브라우저가 지원한다. 같은 원칙이 지금은 지원 시기가 엇갈린 새 기능에 그대로 적용된다. Baseline 연도는 Chrome·Edge·Firefox·Safari가 모두 지원하게 된 해다(Newly available). 그로부터 30개월이 지나면 Widely available이 된다.

기능Baseline
캐스케이드 레이어 @layer2022
컨테이너 크기 쿼리 @container, 서브그리드, :has(), 네이티브 중첩, oklch(), color-mix()2023
상대 색상 문법(oklch(from …)), light-dark(), font-size-adjust, @property, @starting-style·transition-behavior, popover 속성, 블록 레이아웃의 align-content, round()2024
같은 문서 뷰 트랜지션(document.startViewTransition(), View Transitions), @scope, abs()·sign()2025
앵커 위치 지정(팝오버와 앵커 위치 지정), shape(), text-box-trim2026
text-wrap: pretty, 그리드 레인(display: grid-lanes, 메이슨리)아직 아님 (2026년 10월 기준 pretty는 Firefox 미지원, 그리드 레인은 Safari 26.4만 정식 지원)

최신 상태는 web.dev Baseline과 Can I use에서 확인한다.

지원 대상 정하기

  • 추측하지 말고 실제 방문자 분석 데이터를 본다. 모바일에서 못 쓰는 사이트라면 모바일 방문이 적게 잡혀 데이터가 왜곡된다.
  • 데이터가 없으면 Can I Use의 지역별 사용 통계나 Baseline(웹 플랫폼 기능이 모든 주요 브라우저에서 쓸 수 있는지 표시하는 기준)을 참고한다.
  • 사이트의 대상 지역을 잊지 않는다. 저사양 기기와 데이터 절약형 브라우저가 많은 시장에서는 새 기능 지원이 늦다.

지원 등급: 브라우저가 아니라 컴포넌트에 매긴다

지원 범위를 문서로 정하는 고전적인 틀은 Yahoo의 등급별 브라우저 지원(Graded Browser Support) 이다. 「지원」을 똑같은 경험이 아니라 등급으로 나눴다.

등급받는 것QA
A전체 경험(스타일·스크립트·고급 기능)모두 테스트하고 버그를 고친다
C시맨틱 HTML만으로 된 핵심 콘텐츠와 기능대표 브라우저 한두 개, 또는 CSS·JS를 끈 최신 브라우저로 테스트
X알 수 없는·드문 브라우저. 유능하다고 가정하고 A와 같은 것을 준다테스트하지 않는다

C 등급은 블랙리스트, A 등급은 화이트리스트로 브라우저를 미리 분류했다. 막 나온 A 등급 브라우저의 새 버전은 아직 테스트 전이라 X 등급이다.

브라우저 단위 등급에는 한계가 있다. 지금 방문자 대부분은 A 등급이고, 한 브라우저가 어떤 기능은 지원하고 어떤 기능은 지원하지 않는다. 지원 범위는 사다리가 아니라 산점도다. 그래서 컴포넌트마다 등급을 매긴다.

  • 컴포넌트마다 기본 경험과 향상된 경험(필요하면 중간 단계)을 정한다. 예: 데이터 시각화는 기본이 HTML 표, 향상이 Canvas 차트. 내비게이션은 기본이 페이지 이동 링크, 향상이 fetch + history.pushState로 부분 갱신.
  • 어느 단계를 줄지는 브라우저 이름이 아니라 그 컴포넌트가 쓰는 기능의 지원 여부(@supports, 'x' in window)로 정한다.
  • 과거에는 페이지 전체를 두 등급으로 가르는 컷 더 머스터드(Cut the Mustard) 검사를 많이 썼다. 'querySelector' in document && 'addEventListener' in window처럼 몇 가지 기능이 있으면 향상 스크립트를 싣고 없으면 HTML만 준다. 지금은 <script type="module">을 이해하는 브라우저에만 최신 번들을 싣는 것이 같은 역할을 한다.
  • UA로 브라우저를 판별하는 것은 기능 감지가 불가능한 마지막 경우에만 쓴다.

CSS가 이미 가진 두 가지 장치

1. 모르는 CSS는 무시된다

브라우저는 이해하지 못하는 속성과 값을 건너뛴다. 그래서 옛 방식으로 먼저 쓰고 그 아래에 새 방식을 쓰면, 옛 브라우저는 앞부분만, 새 브라우저는 둘 다 읽는다. 같은 선언 안에서도 통한다.

.card {
  background: #3a7;                       /* 폴백 */
  background: oklch(65% 0.15 160);        /* 지원하면 이 값이 이긴다 */
}

2. 새 레이아웃은 옛 레이아웃을 안다

명세에 "그리드·플렉스 아이템이 되면 무엇이 무효가 되는지"가 정의돼 있다. 대부분의 폴백이 자동으로 꺼진다.

폴백으로 쓴 것부모가 display: grid가 되면
float, clear무시된다
display: inline-block아이템에 효과가 없다
display: table-cell그리드 아이템이 되어 테이블처럼 동작하지 않는다
vertical-align무시된다. 대신 박스 정렬(align-self 등)을 쓴다
flex, flex-grow 등무시된다
다단 column-count, column-width무시된다

피처 쿼리로 틈새 메우기

자동으로 꺼지지 않는 값도 있다. 대표적인 것이 아이템에 준 너비다. float 폴백에서 width: 33%를 줬다면, 그리드에서는 이 33%가 컨테이너가 아니라 그리드 영역 기준이 되어 아이템이 셀의 3분의 1만 차지한다.

피처 쿼리(@supports)는 미디어 쿼리처럼 동작하되, 화면 크기 대신 브라우저가 특정 CSS를 지원하는지 묻는다.

/* 1. 폴백: 모든 브라우저가 읽는다 */
.item { float: left; width: 33.333%; }
 
/* 2. 새 레이아웃 */
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
 
/* 3. 틈새로 새는 폴백 값만 되돌린다 */
@supports (display: grid) {
  .item { width: auto; }
}
 
/* 선택자 지원 여부도 물을 수 있다 */
@supports selector(:has(> img)) {
  .card:has(> img) { grid-template-rows: auto 1fr; }
}

피처 쿼리 안에는 새 코드 전체가 아니라 "되돌리거나 덧붙일 값"만 넣는다. @supports not (…)으로 미지원 브라우저 전용 규칙을 쓸 수도 있다. 폴리필도 핵도 아닌, 명세에 정의된 CSS만으로 처리하는 방법이다.

무거운 폴리필을 피하는 이유

  • 레이아웃 전체를 계산하는 기능을 자바스크립트로 흉내 내면 높이·위치를 다시 계산하느라 로딩이 불안정해진다.
  • 미지원 브라우저는 대개 오래되거나 느린 기기다. 가장 약한 기기에 가장 무거운 스크립트를 얹는 셈이다.
  • 줄어들 사용자층 때문에 개발·테스트 시간이 크게 는다.

동작 범위가 좁고 가벼운 폴리필은 예외가 될 수 있다.

변환 도구의 한계

PostCSS·Autoprefixer·Lightning CSS 같은 도구는 접두사를 붙이거나 새 문법을 옛 문법으로 바꿔 준다(예: 네이티브 중첩 → 펼친 선택자, 논리 속성 → 물리 속성). 도구는 문법을 옮길 뿐 동작까지 옮기지는 못한다. 대응 문법이 없는 기능은 조용히 깨지므로 경고를 읽고 결과를 실제 브라우저에서 확인한다.

폴백 테스트

  • 확실한 방법은 기능을 지원하지 않는 실제 브라우저로 보는 것이다. 구버전 브라우저(자동 업데이트를 끈 설치본)나 BrowserStack 같은 원격 테스트 서비스를 쓴다.
  • @supports (display: gridx)처럼 일부러 틀린 값으로 미지원 상태를 흉내 내지 않는다. 피처 쿼리 밖의 새 코드는 여전히 적용돼 거짓 양성이 나기 쉽다.
  • 테스트 대상은 "지원 / 미지원" 두 묶음이면 충분하다.

도입을 설득하는 근거

근거내용
개발 시간새 기능이 복잡도를 줄여 지금과 이후 유지보수 시간을 아낀다
디자인새 기능 없이는 견고하게 만들 수 없는 디자인이다
성능무거운 레이아웃 프레임워크나 스크립트를 걷어낼 수 있다
지원 추세에버그린 브라우저는 자동 업데이트되어 미지원 비율이 빠르게 준다

역사

과거에는 IE10·11이 그리드 초기 명세를 -ms-grid 접두사로만 지원했다. 자동 배치·gap·auto-fill이 없어 아이템을 하나씩 배치하고 간격을 빈 트랙으로 흉내 냈으며, Autoprefixer의 그리드 변환 옵션으로 grid-template-areas를 옮기기도 했다. IE는 2022년 지원이 끝나 이런 우회법은 필요 없다. 피처 쿼리도 IE만 지원하지 않았다.

정리

  • "지원"은 똑같이 보이는 것이 아니라 쓸 수 있는 것이다.
  • 폴백을 먼저 쓰고 새 기능을 아래에 쓴다. 모르는 CSS는 무시되고, 새 레이아웃은 옛 레이아웃을 덮어쓴다.
  • 새어 나오는 값만 @supports 안에서 되돌린다. 선택자 지원은 @supports selector()로 묻는다.
  • 무거운 폴리필 대신 단순한 경험을 준다. 변환 도구 결과는 실제 브라우저로 확인한다.

관련 노트: CSS 그리드 레이아웃, Float와 Flexbox 레이아웃, CSS 커스텀 속성으로 색상 체계 짜기, 반응형 디자인과 다국어 타이포그래피, PostCSS와 CSS 변환 도구, CSS Houdini: 렌더링 엔진에 끼어드는 API

원본 기록11

댓글

GitHub 계정으로 댓글을 남길 수 있어요.