Skip to content

0-3. 웹 표준과 브라우저 지형 ​

한 줄 요약: 웹 표준이 만들어지고 브라우저에 구현되는 구조를 이해하고, 새 플랫폼 기능의 채택 여부를 Baseline과 실패 모드를 근거로 판단할 수 있다.

학습 목표 ​

  • WHATWG / W3C / TC39의 관할과 Living Standard 모델이 버전 기반 표준을 대체한 이유를 설명할 수 있다.
  • 하나의 기능이 제안에서 Baseline까지 도달하는 생애 주기를 단계별로 설명할 수 있다.
  • 브라우저와 렌더링 엔진을 구분하고, 3개 엔진 체제가 갖는 의미를 설명할 수 있다.
  • 새 웹 기능의 도입 여부를 Baseline 상태와 실패 모드의 조합으로 판단할 수 있다.
  • 통념과 스펙이 충돌할 때 1차 자료(스펙, WPT)로 검증할 수 있다.

배경: 왜 이것이 존재하는가 ​

백엔드 개발자는 표준 문서를 읽을 일이 드물다. PostgreSQL의 동작이 궁금하면 PostgreSQL 문서를 보면 되고, 그 문서가 곧 구현의 명세다. 웹은 다르다. 같은 코드를 서로 경쟁하는 회사들이 만든 독립 구현체 3개(Blink, WebKit, Gecko)가 각자 해석해 실행하고, 개발자는 셋 모두에서 같은 결과가 나오기를 기대한다. 이 기대를 성립시키는 유일한 장치가 표준이다. 스펙은 학술 문서가 아니라 구현체 간 상호운용성(interoperability)의 계약서다.

이 구조를 알아야 하는 실무적 이유는 두 가지다. 첫째, 새 기능을 "언제 써도 되는가"라는 판단은 표준화 단계와 구현 현황을 읽을 줄 알아야 내릴 수 있다. 둘째, 브라우저 간 동작이 다를 때 "무엇이 맞는가"의 기준은 다수결도 Chrome도 아니라 스펙이다. 이 커리큘럼이 모든 주제에서 스펙을 1차 자료로 삼는 이유(학습 원칙 4)가 이 문서에서 세워진다.

역사도 한 단락만큼은 필요하다 — 현재 구조가 그 실패의 산물이기 때문이다. 2000년대 W3C는 HTML을 버리고 엄격한 XHTML 2.0으로 가려 했다. 기존 웹과 호환되지 않는 이 방향에 반발한 브라우저 벤더들(Apple, Mozilla, Opera)이 2004년 WHATWG를 결성해 "현실의 웹"을 명세하기 시작했고, 결국 W3C가 이 노선을 수용한 것이 HTML5다. 2019년 양측의 합의로 HTML과 DOM의 관할은 WHATWG로 일원화됐다. 교훈은 명확하다: 웹 표준은 이상적 설계가 아니라 배포된 현실과의 호환을 우선한다. 1-1에서 본 파서 오류 복구의 표준화가 그 정신의 산물이다.

핵심 개념 ​

표준 기구의 지형: 무엇이 어디서 결정되는가 ​

기구관할진행 모델
WHATWGHTML, DOM, Fetch, URL, StreamsLiving Standard (버전 없음, 상시 갱신)
W3C CSSWGCSS 전체 (모듈 단위: Selectors, Grid, …)모듈별 레벨 (CSS Grid Level 2 등)
TC39 (Ecma)JavaScript 언어 (ECMA-262)연 1회 판(edition) + Stage 0~4 프로세스
IETFHTTP, TLS, QUICRFC
WICG / 인큐베이션아직 표준 전 단계의 실험적 제안제안·프로토타입

주소를 알아 두는 실용적 이유: "fetch가 이럴 때 어떻게 동작하지?"의 최종 답은 MDN이 아니라 Fetch Standard에 있다. MDN은 훌륭한 2차 자료지만 요약 과정에서 경계 조건이 생략되곤 한다. 이 커리큘럼에서 스펙 링크를 참고 자료 첫 줄에 두는 이유다.

Living Standard: "버전"이 없는 표준의 논리 ​

HTML에는 더 이상 버전이 없다. "HTML5"는 마케팅 용어로 남았을 뿐, 표준은 HTML Living Standard 하나이고 매주라도 갱신된다. 버전 기반(스냅숏) 모델을 버린 근거는 브라우저의 배포 현실에 있다 — 브라우저는 표준의 특정 버전을 통째로 구현하지 않는다. 기능 단위로 하나씩 출시하고, 그 순서도 벤더마다 다르다. "HTML 5.2를 지원하는 브라우저"라는 개념은 현실에 존재한 적이 없으므로, 버전은 상호운용성 계약으로서 무의미했던 것이다.

Living Standard 모델에서 스펙의 역할은 "완성된 문서"가 아니라 구현들의 합의 상태를 실시간으로 반영하는 저장소다. 실제로 WHATWG 스펙 변경은 GitHub PR로 이뤄지고, 병합 조건에 구현체의 동의와 테스트(뒤에 나올 WPT) 추가가 포함된다. 표준이 먼저 쓰이고 구현이 따라오는 게 아니라, 표준과 구현이 잠금 단계(lockstep)로 움직인다.

JavaScript의 TC39는 같은 정신을 단계(stage) 프로세스로 형식화했다:

  • Stage 0~1 — 아이디어, 문제 제기. 언제든 사라질 수 있다.
  • Stage 2~2.7 — 문법·의미론 초안이 갖춰지고 검토가 시작된다.
  • Stage 3 — 스펙 텍스트 완성. 브라우저들이 실제 구현을 시작하는 단계이며, 구현 과정에서 발견된 문제로 설계가 바뀔 수 있다(예: 배열 그룹핑 제안은 Stage 3에서 웹 호환성 문제로 Array.prototype.group에서 정적 메서드 Object.groupBy로 바뀌었다).
  • Stage 4 — 서로 다른 구현 2개 이상 + test262 테스트 통과. 다음 판의 ECMA-262에 병합된다.

"Stage 3이니 곧 나온다"가 아니라 "Stage 3부터가 진짜 검증"이라는 것, 그리고 2개 독립 구현이 승격 요건이라는 것이 이 프로세스의 핵심이다. 단일 구현의 독주를 표준이 구조적으로 막는다.

브라우저 엔진 지형: 3개의 독립 구현 ​

브라우저와 렌더링 엔진은 다른 층이다. 브라우저는 UI·동기화·검색 등을 포함한 제품이고, 웹 표준을 실제로 구현하는 것은 그 안의 엔진이다.

엔진JS 엔진주요 브라우저주체
BlinkV8Chrome, Edge, Opera, Brave, 삼성 인터넷Google (Chromium)
WebKitJavaScriptCoreSafari, iOS의 모든 브라우저¹Apple
GeckoSpiderMonkeyFirefoxMozilla

¹ iOS에서는 앱스토어 정책상 모든 브라우저가 WebKit을 사용해야 했다. 2024년 EU의 DMA(디지털 시장법) 시행으로 EU 지역에 한해 타 엔진이 허용되기 시작했지만, 이 글 기준으로 실질적 지형 변화는 아직 없다. 실무적 함의: iOS의 Chrome은 Chrome이 아니라 WebKit이다. "Chrome에서 테스트했으니 됐다"가 iOS에서 통하지 않는 이유다.

시장은 Blink로 크게 기울어 있다(Edge가 2020년 자체 엔진을 버리고 Chromium으로 이주한 것이 상징적 사건이다). 이 편중은 양날이다. 개발자 입장에서 "사실상 하나의 엔진"은 편하지만, 단일 구현이 사실상의 표준이 되면 스펙이 아닌 구현의 버그까지 웹의 일부가 된다 — 표준 프로세스가 2개 구현을 요구하는 이유이자, WebKit·Gecko의 존재가 그 자체로 상호운용성의 안전장치인 이유다. 실무 수칙으로 번역하면: 판단 기준을 "Chrome에서 되는가"가 아니라 "3개 엔진이 합의했는가(Baseline)"에 둔다.

기능의 생애 주기와 Baseline ​

하나의 기능이 개발자 손에 오기까지의 경로를 알면, 어느 단계의 기능인지에 따라 다르게 대할 수 있다.

제안(WICG/TC39 초안)
  → 실험 구현 (플래그 뒤에서만 동작)
  → Origin Trial (Chrome: 신청한 사이트에 한해 프로덕션 실험)
  → 정식 출시 (한 엔진에서 ship)
  → 다른 엔진들 후속 구현
  → Baseline Newly available   ← 3대 엔진의 최신 안정판이 모두 지원
  → Baseline Widely available  ← Newly로부터 30개월 경과

Baseline은 Google·Mozilla·Apple 등이 참여하는 WebDX 그룹이 정의한 호환성 신호다. 기준이 명확하다:

  • Newly available — Chrome, Edge, Firefox, Safari의 최신 안정 버전이 모두 지원하기 시작한 시점.
  • Widely available — Newly available로부터 30개월이 지난 시점. 사용자 대부분의 브라우저가 업데이트를 받았다고 볼 수 있는 기간이다.

30개월이라는 숫자의 근거는 브라우저의 자동 업데이트 보급 곡선이다 — 에버그린(evergreen, 자동 상시 업데이트) 브라우저 체제에서 신기능이 실사용자 대다수에 도달하는 데 걸리는 시간을 보수적으로 잡은 것이다. 뒤집어 말하면 Baseline의 경계 조건도 여기 있다: 자동 업데이트 바깥의 집단(기업 관리 브라우저, 오래된 iOS 기기 — Safari 버전은 OS에 묶인다)이 주 사용자라면 Widely available도 충분 조건이 아니다. Baseline은 실사용 통계가 아니라 지원 시작 시점 기반의 신호이므로, 최종 판단에는 자기 서비스의 실제 사용자 브라우저 분포(analytics)를 겹쳐야 한다.

실무 관점 ​

채택 판단 프레임: Baseline 상태 × 실패 모드 ​

"이 기능 써도 되나요"는 Baseline 상태 하나로 답할 수 없다. 미지원 브라우저에서 어떻게 실패하는가가 나머지 절반이다.

실패 모드예판단
우아하게 무시됨 (점진적 향상)CSS :has(), text-wrap: balance, loading="lazy"Newly available만 돼도, 심지어 전이라도 쓸 수 있다 — 미지원 환경은 조금 덜 좋을 뿐
폴백을 짝지을 수 있음새 CSS 값, @supports 분기폴백 작성 비용과 비교해 결정 (1-3의 폴백 관용구)
폴리필 가능새 JS API폴리필 크기·충실도 비용을 지불하면 즉시 사용 가능 (0-2)
기능이 통째로 실패핵심 동작이 그 API에 의존 (폴리필 불가: 예 Proxy 기반)Widely available + 자사 사용자 분포 확인 전엔 도입 불가

같은 Newly available이라도 첫 행의 기능은 오늘 써도 되고, 마지막 행의 기능은 2년 반을 기다려야 한다. Baseline은 입력값이지 결론이 아니다.

기능 탐지로 분기하고, UA 스니핑은 쓰지 않는다 ​

미지원 환경 분기가 필요할 때의 표준 수단은 그 기능 자체를 검사하는 기능 탐지(feature detection)다:

js
// ❌ UA 스니핑 — UA 문자열은 위장의 역사이며(모든 브라우저가 "Mozilla/5.0"로
//    시작하는 이유), Chrome은 UA 정보 축소를 진행해 신뢰도가 계속 떨어진다
if (navigator.userAgent.includes('Safari')) { /* ... */ }

// ✅ 기능 탐지 — 필요한 능력 그 자체를 검사한다
if ('IntersectionObserver' in window) { /* ... */ }
css
/* ✅ CSS의 기능 탐지 */
@supports (container-type: inline-size) { /* ... */ }

UA 스니핑이 안티패턴인 근거는 역사가 증명한다. 브라우저를 보고 분기한 코드는 "그 브라우저가 나중에 기능을 지원하게 되어도" 계속 구식 경로로 보내며, 이를 회피하려고 브라우저들이 서로의 UA를 사칭하면서 UA 문자열 자체가 신뢰 불가능해졌다.

브라우저마다 동작이 다를 때: 검증 절차 ​

동작 차이를 만나면 "어느 쪽이 버그인가"를 정하는 절차가 있다.

  1. 스펙 확인 — 해당 동작을 정의한 스펙 조항을 찾는다. MDN 페이지 하단의 Specifications 표가 조항으로 바로 연결된다.
  2. WPT 확인 — web-platform-tests에서 해당 기능의 테스트를 검색하면 엔진별 통과/실패가 그대로 보인다. 스펙 해석이 갈리는 지점은 대개 이미 테스트로 문서화되어 있다.
  3. 버그 트래커 — 스펙과 다른 쪽 엔진의 이슈 트래커에서 알려진 버그인지 확인하고, 없으면 리포트한다.

이 절차의 요점은 "다수결(Chrome처럼 동작하는 쪽이 정답)"이 아니라는 것이다. 실제로 Chrome이 스펙 위반이고 Safari가 맞는 사례도 드물지 않다.

더 깊이 ​

web-platform-tests와 Interop: 상호운용성의 계량화 ​

Living Standard 모델에서 "구현들의 합의"를 검증 가능하게 만드는 물리적 실체가 web-platform-tests(WPT) 다. 3대 엔진이 공유하는 수십만 개의 크로스 브라우저 테스트 스위트로, 스펙 변경 PR에는 대응하는 WPT 추가가 요구되고, 각 엔진은 WPT를 CI에서 상시 실행한다. 표준 문서(산문)와 구현(코드) 사이를 잇는 실행 가능한 명세인 셈이다 — 백엔드로 치면 API 스펙에 딸린 공식 컨포먼스 테스트다.

이 위에서 2022년부터 매년 진행되는 Interop 프로젝트는 벤더들이 "올해 상호운용성을 맞출 영역"을 공동 선정하고 WPT 통과율로 진척을 공개 계량하는 협약이다. Flexbox·Grid의 엔진 간 미묘한 차이가 크게 줄어든 것이 이 체제의 성과다. 실무적 용도: 특정 기능의 엔진 간 신뢰도가 궁금하면 wpt.fyi의 통과율과 Interop 대상 여부가 정량적 답을 준다.

vendor prefix의 실패: 실험 채널의 설계 변경 ​

-webkit-border-radius처럼 접두사를 붙여 실험 기능을 내보내던 vendor prefix 체제는 실패한 설계로 판명됐다. 실험 기능임에도 개발자들이 프로덕션에 썼고, 모바일 웹이 WebKit 위주로 작성되자 다른 엔진들이 호환성을 위해 -webkit- 접두사를 구현하는(Gecko는 지금도 일부 -webkit- 별칭을 지원한다) 역전이 일어났다. 실험 표기가 사실상의 표준으로 굳어 버린 것이다.

교훈은 "실험 기능은 시간이 지나면 자동으로 제거되어야 한다"였고, 그 결과가 현재의 채널 설계다: 플래그(개발자 개인 환경에서만), Origin Trial(등록 사이트에 한해 만료 기한이 있는 토큰으로 프로덕션 실험). Origin Trial은 사용량이 일정 비율을 넘으면 자동 중단되는 안전장치까지 갖췄다 — 실험 기능에 웹이 의존하게 되는 것을 구조적으로 차단하는 설계다. 오래된 코드베이스에서 만나는 접두사 속성들은 이 실패한 체제의 화석이며, 현재는 autoprefixer 같은 도구가 필요한 경우에만 기계적으로 붙인다.

스펙을 읽는 법: 알고리즘 산문 ​

WHATWG 계열 스펙은 서술이 아니라 의사코드에 가까운 알고리즘으로 쓰여 있다. "To fetch a resource, run these steps: 1. Let request be … 2. If … then return a network error"처럼, 변수 선언(Let)과 단계 실행으로 구성된다. 처음에는 낯설지만, 이 형식 덕분에 경계 조건의 답이 항상 결정적으로 나온다 — "이 경우엔 어떻게 되지?"에 대해 스펙은 반드시 어느 단계에서 무엇을 반환하는지 명시한다. 이 커리큘럼 Phase 2에서 ==의 판정 규칙이나 Promise 처리를 다룰 때 이 알고리즘 산문을 직접 읽는다. 읽는 요령 하나: 스펙의 "must"는 구현체(브라우저)에 대한 요구이고, 개발자에 대한 요구가 아니다.

정리 ​

  • 웹 표준은 경쟁사들이 만든 3개 독립 구현(Blink/WebKit/Gecko)이 같은 결과를 내게 하는 상호운용성 계약이며, 이상적 설계보다 배포된 현실과의 호환을 우선한다.
  • Living Standard와 TC39 스테이지 프로세스는 "브라우저는 표준의 버전을 구현하지 않는다"는 현실을 반영해, 표준과 구현이 잠금 단계로 움직이는 모델이다. 독립 구현 2개가 승격 요건이다.
  • iOS의 모든 브라우저는 (EU 외 지역에서) WebKit이다. "Chrome에서 확인"은 iOS 검증이 아니다.
  • Baseline Newly available은 3대 엔진 최신판의 지원 시작, Widely available은 그로부터 30개월이다. 채택 판단은 Baseline 상태에 실패 모드(우아한 무시/폴백/폴리필/전면 실패)와 자사 사용자 분포를 겹쳐 내린다.
  • 브라우저 간 동작이 다를 때의 기준은 다수결이 아니라 스펙이고, wpt.fyi에서 엔진별 준수 현황을 정량으로 확인할 수 있다.

확인 문제 ​

  1. 팀 동료가 "이 CSS 기능은 Baseline Newly available이니 바로 쓰자"고 했고, 다른 동료는 "Widely available까지 기다려야 한다"고 했다. 둘 다 틀릴 수 있는 이유를 이 문서의 판단 프레임으로 설명하라.
정답과 해설

Baseline 상태만으로는 결론이 나지 않는다. 실패 모드가 빠져 있기 때문이다. 그 기능이 미지원 브라우저에서 우아하게 무시되는 장식적 속성이거나 @supports 폴백을 짝지을 수 있다면 Newly available(혹은 그 전)이라도 쓸 수 있으므로 "기다리자"가 과잉 보수다. 반대로 핵심 UX가 그 기능에 통째로 의존하고 폴백이 불가능하다면, Widely available이 되어도 자사 사용자에 자동 업데이트 밖 집단(구형 iOS, 기업 관리 브라우저)이 많으면 부족하므로 "바로 쓰자"도 틀린다. 올바른 판단은 Baseline 상태 × 실패 모드 × 실사용 브라우저 분포의 3개 입력으로 내린다.

  1. 여러분의 코드가 Chrome에서는 의도대로, Safari에서는 다르게 동작한다. "Safari 버그"라고 결론 내리기 전에 밟아야 할 절차와, 그 절차가 "Chrome처럼 동작하는 게 정답"이라는 직관보다 나은 이유를 설명하라.
정답과 해설

절차: ① 해당 동작을 정의한 스펙 조항을 찾는다(MDN Specifications 표 활용). ② wpt.fyi에서 관련 테스트의 엔진별 통과 현황을 본다. ③ 스펙과 어긋난 쪽 엔진의 버그 트래커를 확인한다. 시장 점유율은 표준 준수와 무관하므로 "다수 사용자의 브라우저처럼 동작하는 것"은 정답의 근거가 못 된다 — Chrome이 스펙을 위반하고 Safari가 준수하는 사례도 실제로 있다. 스펙을 기준으로 삼아야 하는 실용적 이유도 있다: 버그인 쪽은 언젠가 스펙 방향으로 수정되므로, Chrome의 비표준 동작에 맞춘 코드는 미래의 Chrome에서 깨진다.

  1. TC39 프로세스는 Stage 4 승격에 "서로 다른 구현 2개 이상"을 요구하고, WHATWG는 스펙 병합에 구현체들의 동의를 요구한다. 이 요건이 없다면 어떤 일이 일어나는지, vendor prefix의 역사를 근거로 추론하라.
정답과 해설

단일 구현이 먼저 출시되고 개발자들이 그 위에 코드를 쌓으면, 그 구현의 세부 동작(버그 포함)이 사실상의 표준이 된다. 이후 다른 엔진은 스펙이 아니라 선발 구현의 동작을 역공학으로 재현해야 하고, 설계 결함이 발견되어도 웹 호환성 때문에 고칠 수 없게 된다. vendor prefix 시대가 정확히 이 경로였다 — 모바일 웹이 -webkit-에 의존하자 경쟁 엔진들이 접두사를 사칭 구현했고, 실험 문법이 제거 불가능한 화석이 됐다. 복수 구현 요건은 "한 벤더의 결정이 곧 웹이 되는" 경로를 구조적으로 차단하고, 구현 과정에서 설계 결함을 표준 확정 전에 드러내는 장치다(Object.groupBy 개명 사례).

참고 자료 ​

  • WHATWG — FAQ — Living Standard 모델의 근거와 W3C와의 관계 정리.
  • TC39 Process Document — Stage 0~4 각 단계의 승격 요건 원문.
  • web.dev — Baseline — Newly/Widely available의 정의와 30개월 기준의 설명.
  • wpt.fyi — 기능별·엔진별 web-platform-tests 통과 현황 대시보드. 상호운용성 판단의 정량 근거.
  • MDN — Browser compatibility data — caniuse와 함께 MDN 호환성 표의 원천 데이터.
  • Interop 2025 — 올해 벤더들이 합의한 상호운용성 개선 영역과 진척도.