노트

CSS-in-JS와 빌드 타임 CSS

CSS-in-JS

프런트엔드#css#react · 연결된 개념 6개

쉽게 말하면

CSS-in-JS는 화면을 그릴 때마다 그 자리에서 옷을 재단해 입히는 방식이고, 빌드 타임 CSS는 미리 만들어 둔 옷을 꺼내 입히는 방식이에요. 즉석 재단은 편하지만 매번 시간이 들어서 요즘은 미리 만드는 쪽이 늘었어요.

비유가 깨지는 곳 느린 것만 문제는 아니에요. 스타일을 만들려면 클라이언트 런타임이 필요해 서버 컴포넌트에서 바로 못 쓰고, 스트리밍 SSR에선 스타일을 모아 넣는 방식이 꼬여요. 런타임 값은 CSS 변수로 넘기면 돼요.

JS(JavaScript) 안에서 스타일을 정의하고, 렌더링할 때 라이브러리가 클래스를 만들어 style 태그로 주입하는 방식. styled-components와 Emotion이 대표다. React 18 이후 서버 컴포넌트(React Server Components)·스트리밍 SSR(Streaming Server-Side Rendering)이 자리 잡으면서 런타임에 CSS를 만드는 방식은 줄고, 빌드할 때 CSS를 뽑는 방식이 늘었다(2026 기준).

유행했던 이유

  • 클래스 이름을 해시로 만들어 전역 충돌을 없앴다
  • props로 스타일을 바꾸는 등 JS 값과 자연스럽게 연결됐다
  • 컴포넌트와 스타일을 한 파일에 묶을 수 있었다

밀려난 이유

  • 런타임 비용: 렌더링 → CSS 문자열 생성 → style 삽입 → 스타일 재계산이 매번 끼어든다. 라이브러리 런타임도 번들에 들어간다 → 번들 크기 줄이기
  • 서버 컴포넌트와 맞지 않는다: 스타일을 만들려면 클라이언트 런타임(Context 등)이 필요해서 서버 컴포넌트에서 바로 쓸 수 없다
  • 스트리밍 SSR: HTML을 조각조각 보내면 "다 렌더링한 뒤 스타일을 모아 넣는" 기존 방식이 꼬인다. 서버와 클라이언트의 클래스가 어긋나면 하이드레이션(Hydration) 불일치도 생긴다
  • 재사용 방식도 styled(Button) 상속에서 variant·size props를 받는 컴포넌트 API로 옮겨 갔다

대안

  • Tailwind: 빌드 때 정적 CSS 생성, 서버 컴포넌트에서 그냥 쓴다
  • CSS Modules: 파일 단위 스코프, 여전히 많이 쓴다
  • Vanilla Extract·Panda CSS·StyleX: TS(TypeScript)로 쓰되 빌드 때 CSS 파일로 뽑는 "제로 런타임" 계열

런타임 값이 많은 경우(진행률 width, 사용자가 고른 색)는 인라인 스타일이나 CSS 변수로 넘기면 된다. 이 선택은 결국 "스타일을 언제 만드느냐"의 문제다. Sass와 PostCSS가 빌드 단계 안에서의 선택이라면, 이것은 빌드냐 런타임이냐의 선택이다.

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 브라우저 렌더링 파이프라인

    브라우저가 받은 HTML·CSS·JS를 화면의 픽셀로 바꾸는 순서. 처음 로드할 때도, 이후 무언가 바뀔 때도 같은 단계를 거친다. 바뀐 내용에 따라 어느 단계부터 다시 시작하는지만 다르다.

  • CSR·SSR·SSG·ISR

    렌더링 전략은 HTML(HyperText Markup Language)을 언제, 어디서 만드느냐의 선택이다. 브라우저에서 만들면 CSR(Client-Side Rendering), 요청마다 서버에서 만들면 SSR(Server-Side Rendering), 빌드 때 미리 만들면 SSG(Static Site Generation), 미리 만든 것을 주기적으로 다시 만들면 ISR(Incremental Static Regeneration)이다.

  • CSS 명시도

    캐스케이드에서 레이어까지 비겼을 때, 선택자가 요소를 얼마나 구체적으로 가리키는지로 승부를 내는 점수. (A, B, C) 세 자리로 매기고 앞자리부터 비교한다.

  • NestJS

    NestJS는 TypeScript를 전제로 모듈·의존성 주입(Dependency Injection, DI)·데코레이터(decorator) 구조를 제공하는 Node.js 서버 프레임워크다. 2017년 Kamil Myśliwiec가 만들었고, 구조를 강제하는 방식 때문에 흔히 "Node.js의 Spring"이라 불린다.

  • tailwind-merge와 cn()

    같은 CSS 속성을 건드리는 Tailwind 클래스가 여러 개 붙었을 때, 뒤에 온 것만 남기고 앞의 것을 지워 주는 라이브러리. 컴포넌트의 기본 클래스를 사용처에서 덮어쓰는 패턴을 안전하게 만든다.

보기 옵션