크로스 브라우징은 브라우저 종류·버전·기기가 달라도 웹 페이지가 같은 기능을 제공하도록 만드는 일이다. 모든 브라우저에서 픽셀까지 똑같이 보이게 하는 것이 목표가 아니라, 지원하기로 한 환경에서 핵심 기능이 동작하고 오래된 환경에서도 쓸 수는 있게(점진적 향상, Progressive Enhancement) 하는 것이 목표다.
순서
- 지원 범위 정하기: 실제 사용자 통계를 보고 지원할 브라우저를 정한다. 보통
package.json이나.browserslistrc에 Browserslist 쿼리(> 0.5%, last 2 versions, not dead)로 적어 두고, 빌드 도구들이 같은 목록을 읽게 한다 - 쓰기 전에 확인: 새 기능은 MDN의 브라우저 호환성 표나 Can I use로 지원 여부를 본다
- 빌드에서 메우기
- 문법: Babel·SWC·esbuild가 최신 JS 문법을 지원 대상에 맞게 낮춘다(트랜스파일, transpile)
- API:
Promise.allSettled처럼 런타임에 없는 기능은 폴리필(Polyfill)로 채운다. 필요한 것만 넣어야 번들이 커지지 않는다 → 번들 크기 줄이기 - CSS: PostCSS의 Autoprefixer가 벤더 접두사(
-webkit-)를 붙인다 → Sass와 PostCSS
- 코드에서 분기하기: 브라우저 이름(User-Agent)이 아니라 기능이 있는지 확인한다(기능 감지, Feature Detection)
if ('IntersectionObserver' in window) {
observeImages()
} else {
loadAllImages() // 대체 동작
}.layout { display: flex; }
@supports (display: grid) {
.layout { display: grid; }
}- 기본 스타일 맞추기: 브라우저마다 다른 기본 스타일은 CSS 리셋으로 정리한다
- 실제 기기에서 확인: 특히 iOS에서는 모든 브라우저가 WebKit 엔진을 쓰므로 Safari 버전이 사실상 지원 범위다. EU처럼 규제로 다른 엔진이 허용된 지역은 예외다(2026 기준). 앱 안의 웹뷰도 따로 확인한다. 실기기가 없으면 원격 테스트 서비스를 쓴다
자주 부딪히는 곳
- 모바일 브라우저(특히 iOS Safari)의
100vh는 주소창이 접힌 큰 뷰포트 기준이라 주소창이 보이면 화면을 넘친다 →100dvh(동적 뷰포트 단위)나100svh(작은 뷰포트 단위) - 날짜 문자열 파싱 형식 차이(
new Date('2026-10-07 10:00')) → 표준 형식이 아닌 문자열의 해석은 구현마다 다르므로 ECMAScript가 정한 ISO 8601 기반 형식(2026-10-07T10:00)으로 쓴다 :has(), 컨테이너 쿼리 같은 비교적 새 CSS →@supports로 대체 스타일을 둔다
명세: W3C — CSS Conditional Rules Level 3: @supports · W3C — CSS Values and Units Level 4: 큰·작은·동적 뷰포트 · ECMAScript — Date Time String Format 출처: MDN — Introduction to cross-browser testing · MDN — Implementing feature detection · MDN — Polyfill