헷갈리는 이유: "runtime" 이 두 축에서 쓰입니다. ① CSS 를 언제 만드나(생성 시점) ② 브라우저에서 스타일용 JS 가 도나(런타임 비용).
CSS 를 별도 .css 파일이 아니라 JS/TS 코드 안에서 작성하는
방식. 라이브러리가 클래스명을 자동 생성·스코프 격리해 줍니다. (예: MUI
Emotion, styled-components, Panda, vanilla-extract)
flex, px-4 같은 작은 단위 클래스를 조합해
스타일링. 빌드 때 사용한 클래스만 CSS 로 생성. CSS-in-JS 가 아닙니다.
(예: Tailwind, shadcn)
버튼·카드 등 완성된 컴포넌트를 제공하는 묶음. (예: MUI, Chakra UI) — 내부 스타일 엔진은 별개(MUI=Emotion runtime, Chakra v3=Panda 기반).
| 구분 | CSS 를 만드는 시점 | 결과 |
|---|---|---|
| build-time | 개발자가 빌드(bun run build)할 때 |
정적 .css 로 미리 추출 |
| runtime | 사용자가 페이지를 열어 브라우저에서 JS 실행될 때 | JS 가 <style> 을 동적 주입 |
zero runtime: 브라우저에서 스타일 생성을 위해 도는 JS 가 0. 보통 build-time 의 결과입니다(미리 다 구워둠 → 브라우저는 완성된 CSS 만 로드). runtime: 스타일 엔진 JS 가 브라우저에서 동작 → 약간의 비용, 대신 props 기반 동적 스타일에 유연.
비유 — zero runtime: 미리 구워둔 빵(바로 가져감) · runtime: 주문 시 굽는 빵(유연하지만 매번 작업).
| 프레임워크 | 분류 | 런타임 |
|---|---|---|
| Tailwind | 유틸리티 CSS | zero runtime |
| shadcn/ui | 유틸리티 CSS (Tailwind + Radix) | zero runtime |
| Panda CSS | CSS-in-JS (build-time) | zero runtime |
| vanilla-extract | CSS-in-JS (build-time) | zero runtime |
| Chakra UI v3 | 컴포넌트 라이브러리 (Panda 기반) | zero runtime |
| MUI | 컴포넌트 라이브러리 (Emotion) | runtime |
| styled-components | CSS-in-JS | runtime |
렌더링(런타임)·로딩(FCP)·번들 크기 세 축으로 비교합니다. 렌더링은 아래 버튼으로 즉석 측정하고, FCP 는 프레임 로드 시 자동 수집됩니다.
측정 시점: 버튼 클릭 시 실시간. 선택한 개수의 컴포넌트를 각
프레임이 한 번에 렌더하는 시간(mount)과, 그 전체를 한 번 더 그리는
시간(update)을 잽니다. flushSync 로 React 렌더+커밋을
동기 실행해 그 앞뒤 시간차를 측정 — CSS-in-JS 가 커밋 때 스타일을
생성·주입하는 비용이 그대로 잡힙니다(브라우저 페인트는 제외해 프레임
경계로 값이 뭉치지 않음). runtime CSS-in-JS(MUI·styled-components)는
컴포넌트마다 스타일을 만들어 비용이 커지고, zero-runtime 계열은
가볍습니다. iframe 이 lazy 로드라
스크롤해 모든 프레임을 띄운 뒤
실행하세요. 환경에 따라 달라져 절대값보다 상대 비교용입니다.
이 팝업이 프레임을 가려도 측정 이득은 없습니다. 측정을
flushSync 기반으로 하기 때문입니다 — React 의 렌더 +
커밋(DOM 생성 + CSS-in-JS 스타일 규칙 주입)까지만 동기로 재고,
브라우저 페인트(화면에 픽셀 찍기)는 측정에서 제외합니다. "가려짐"이
줄여줄 수 있는 비용은 오직 페인트인데, 그 페인트가 애초에 측정값에
없으니 가려지든 아니든 값은 같습니다. 또 다른 요소에 z-index 로 덮인
것은 display:none 과 달라서, 가려진 iframe 도 JS·layout·
스타일 주입을 그대로 다 수행합니다(7/7 프레임 응답이 그 증거). 7 개
프레임이 동일 조건으로 덮이므로 상대 비교에도 영향이 없습니다.
마운트 (mount)
리렌더 (update)
측정 시점: 각 프레임 로드 시 실시간 (새로고침마다 재측정). 각 프레임이 처음 화면을 그리기까지 시간(First Contentful Paint). iframe 이 화면에 보일 때 측정되므로 스크롤해 모두 로드한 뒤 확인하세요. 환경·캐시에 따라 달라져 절대값보다 상대 비교용입니다.
같은 데모를 프로덕션 빌드(bun run build)했을 때 dist
크기. React(gzip ~45KB) 포함 전체. 전송·파싱 비용의 직접 지표이며,
숫자가 작을수록 가볍습니다. (런타임 비용은 "용어 설명" 참고)
측정 시점: 빌드 시 1회(수동 입력 고정값) · 기준 빌드 2026-06-01 (각 프레임 최신 버전). 코드·버전 변경 시 자동 갱신되지 않습니다.
| 프레임워크 | JS | CSS | 합계 (gzip) |
|---|---|---|---|
| vanilla-extract | 148.4KB (47.9) | 2.6KB (0.8) | 48.7KB |
| Tailwind | 149.6KB (48.2) | 11.7KB (3.2) | 51.4KB |
| Panda CSS | 163.9KB (53.6) | 18.5KB (5.6) | 59.2KB |
| styled-components | 180.6KB (60.4) | — | 60.4KB |
| shadcn/ui | 195.6KB (62.6) | 11.8KB (3.2) | 65.8KB |
| MUI | 379.2KB (120.5) | — | 120.5KB |
| Chakra UI | 440.4KB (125.6) | — | 125.6KB |
※ MUI/Chakra 는 컴포넌트 라이브러리라 완성 컴포넌트·접근성·테마 시스템이 포함돼 큽니다(트레이드오프). CSS-in-JS(MUI·styled·Chakra)는 스타일이 JS 런타임에 주입돼 별도 CSS 파일이 없습니다.