디자인 시스템의 성능: CSS-in-JS와 CSS Variables의 런타임 비용 분석

디자인 시스템 성능 분석: CSS-in-JS와 CSS Variables 런타임 비용 비교

CSS-in-J

디자인 시스템을 야심 차게 도입하고 컴포넌트 라이브러리를 구축했는데, 정작 복잡한 대시보드나 리스트 페이지에서 화면이 버벅거리는 현상을 겪어보셨나요? 범인은 로직이 아니라 여러분이 선택한 ‘스타일링 방식’일 가능성이 매우 높습니다. 특히 수백 개의 디자인 토큰이 실시간으로 적용되는 환경에서 스타일을 계산하고 주입하는 방식의 차이는 서비스의 첫인상인 ‘반응 속도’를 결정짓는 핵심 변수가 됩니다.

이 글에서는 현대 웹 개발의 주류인 CSS-in-JS(Styled-components, Emotion 등)와 브라우저 네이티브 기술인 CSS Variables가 런타임 성능에 어떤 영향을 미치는지, 그리고 디자인 시스템 엔지니어로서 어떤 기술 스택을 선택해야 ‘성능’과 ‘유지보수’라는 두 마리 토끼를 잡을 수 있을지 실무 관점에서 분석해 드립니다.

CSS-in-JS의 편리함이 숨기고 있는 ‘런타임 세금’

Styled-components나 Emotion 같은 라이브러리는 개발자에게 극상의 DX(Developer Experience)를 제공합니다. 자바스크립트 변수를 스타일 코드에 직접 넣고, props에 따라 스타일을 동적으로 변경하는 것은 매우 직관적이죠. 하지만 이 편리함 뒤에는 브라우저가 매번 지불해야 하는 ‘런타임 비용’이 숨어 있습니다.

CSS-in-JS 라이브러리는 컴포넌트가 렌더링될 때마다 자바스크립트 단에서 스타일 코드를 파싱하고, 고유한 클래스명을 생성(Hashing)하여 <style> 태그에 주입합니다. 컴포넌트가 작을 때는 체감되지 않지만, 수천 개의 요소가 있는 페이지에서 테마를 바꾸거나 동적 스타일을 적용하면 메인 스레드가 스타일 계산에 점유되어 ‘프레임 드랍’이 발생하게 됩니다. 특히 리액트의 리렌더링 사이클과 맞물리면 이 비용은 기하급수적으로 증가합니다.

[💡 에디터의 실무 팁: 런타임 CSS-in-JS를 꼭 써야 한다면, 가급적 동적 props 사용을 줄이고 스타일 정의를 컴포넌트 외부로 빼서 선언하세요. 매 렌더링마다 스타일 객체가 새로 생성되는 것을 막는 것만으로도 성능 저하를 눈에 띄게 줄일 수 있습니다.]

CSS Variables: 브라우저가 직접 계산하는 가장 빠른 방법

반면 CSS Variables(Custom Properties)는 자바스크립트의 도움 없이 브라우저 엔진이 직접 값을 관리합니다. 디자인 토큰을 :root에 CSS 변수로 선언해두면, 자바스크립트는 오직 최상위 노드의 속성값만 바꾸면 됩니다. 스타일의 재계산과 적용은 브라우저의 렌더링 파이프라인 안에서 하드웨어 가속을 받으며 수행되므로, 자바스크립트 실행 시간이 거의 제로에 가깝습니다.

특히 다크 모드 전환이나 브랜드 테마 변경 시 CSS Variables의 위력은 압도적입니다. CSS-in-JS는 모든 컴포넌트의 스타일을 새로 생성하고 주입해야 하지만, CSS Variables는 단순히 클래스명 하나를 바꾸는 것만으로 브라우저가 알아서 모든 하위 요소의 스타일을 즉시 갱신합니다. 런타임 비용 관점에서 보면 네이티브 기술이 압승할 수밖에 없는 구조인 셈입니다.

실무 비교 분석: 성능과 유연성의 균형

두 기술의 특성을 표로 정리하면 다음과 같습니다. 디자인 시스템의 성격에 따라 적절한 선택이 필요합니다.

분석 항목 런타임 CSS-in-JS CSS Variables
렌더링 성능 스타일 주입 시 메인 스레드 점유 브라우저 네이티브 가속 (매우 빠름)
동적 스타일 JS Props 기반 (매우 유연함) CSS 속성 기반 (제한적이지만 충분함)
번들 크기 라이브러리 용량 추가 (약 10~15KB) 추가 용량 없음
테마 전환 전체 컴포넌트 리렌더링 유발 가능 CSS 상속을 통한 즉시 전환

 

실제로 제가 진행했던 한 금융 플랫폼 리뉴얼 프로젝트에서는 모든 스타일을 CSS-in-JS의 동적 props로 관리하다가, 차트 데이터가 실시간으로 업데이트될 때마다 전체 화면이 멈추는 현상이 발생했습니다. 해결책은 의외로 간단했습니다. 자주 바뀌는 스타일 값(색상, 투명도 등)만 CSS Variables로 교체하고 CSS-in-JS는 정적인 구조만 담당하게 했더니, 스크립트 실행 시간이 70% 이상 단축되었습니다.

[💡 에디터의 실무 팁: 최근 트렌드는 ‘Zero-runtime CSS-in-JS'(Vanilla Extract, Panda CSS)입니다. 빌드 타임에 스타일을 생성하면서도 CSS Variables를 내부적으로 활용하여 DX와 성능을 모두 잡는 방식이죠. 신규 프로젝트라면 이 선택지를 강력히 추천합니다.]

트러블슈팅: 애니메이션과 스타일 주입의 충돌 해결

애니메이션이 진행되는 도중에 CSS-in-JS가 스타일 태그를 새로 주입하면 브라우저는 레이아웃을 다시 계산(Reflow)해야 합니다. 이 과정에서 애니메이션이 뚝뚝 끊기는 ‘Jank’ 현상이 나타나죠. 만약 디자인 시스템의 슬라이더나 모달이 부드럽지 않다면, 자바스크립트로 위치값을 계산해 스타일로 주입하고 있지는 않은지 확인해 보세요.

이런 경우에는 위치값(x, y)을 CSS Variables로 선언하고 자바스크립트에서는 element.style.setProperty('--x', value) 방식만 사용하는 것이 훨씬 매끄럽습니다. 브라우저는 CSS 변수의 변경을 ‘합성(Composite)’ 단계에서 효율적으로 처리하기 때문입니다. 기술의 화려함보다 브라우저의 렌더링 원리를 이해하는 것이 성능 최적화의 첫걸음입니다.

자주 묻는 질문(FAQ)

Q1. CSS Variables는 구형 브라우저에서 지원되지 않지 않나요? 2026년 현재, 인터넷 익스플로러(IE)는 공식적으로 종료되었으며 모든 현대 브라우저(Edge, Chrome, Safari, Firefox)는 CSS Variables를 완벽하게 지원합니다. 더 이상 구형 브라우저 대응 때문에 성능을 포기할 필요는 없습니다.

Q2. Tailwind CSS와 디자인 토큰 연동 시 성능 문제는 없나요? Tailwind는 빌드 시점에 정적인 CSS 파일을 생성하므로 런타임 비용이 거의 없습니다. 테일윈드 설정 파일에 디자인 토큰을 CSS Variables 형식으로 연결해두면, 성능과 테마 전환의 유연성을 동시에 확보할 수 있는 가장 현대적인 조합이 됩니다.

Q3. 런타임 CSS-in-JS를 완전히 제거해야 할까요? 반드시 그럴 필요는 없습니다. 사용자가 적고 컴포넌트가 단순한 페이지라면 편리한 DX를 누리는 것이 이득일 수 있습니다. 다만, 대규모 데이터 처리나 복잡한 인터랙션이 핵심인 서비스라면 점진적으로 CSS Variables나 Zero-runtime 방식으로 마이그레이션하는 전략이 필요합니다.

댓글 남기기