프레임워크\라이브러리/CSS

[라이브러리] Vanilla Extract란?

thinktank911 2025. 11. 18. 23:46

Vanilla Extract란?

Zero-runtime CSS in JS 라이브러리. 

 

CSS-in-JS는 말 그대로 "JavaScript 안에서 CSS를 작성하는 방식"이다.
즉, 스타일을 별도의 CSS 파일이 아니라 JavaScript 코드 안에서 작성하는 것.
대표적인 CSS-in-JS 라이브러리로는 Styled-Components, Emotion, JSS 등이 있다.

 

CSS-in-JS의 장점

✅ 컴포넌트와 스타일을 함께 관리할 수 있음
웹페이지의 구성 요소(컴포넌트)와 스타일을 하나의 파일 안에서 함께 작성할 수 있어 유지보수가 쉽다.
스타일이 특정 컴포넌트에 종속되므로 다른 곳에서 스타일이 섞이는 일이 줄어든다.

✅ 동적으로 스타일을 변경하기 쉬움
JavaScript 변수를 활용해 색상, 크기, 여백 등의 값을 변경할 수 있다.
예를 들어, 버튼의 색상을 사용자 설정에 맞게 변경하는 것이 가능하다.

✅ 사용하지 않는 스타일이 자동 정리됨
전통적인 CSS 방식에서는 필요 없는 스타일이 파일에 남아 있는 경우가 많은데, CSS-in-JS는 사용하지 않는 스타일을 자동으로 제거하여 코드 최적화가 가능

CSS-in-JS의 단점

❌ 초기 로딩 속도가 느릴 수 있음
스타일이 JavaScript 코드 안에서 실행되므로, 브라우저가 화면을 표시하는 데 시간이 조금 더 걸릴 수 있다.

❌ 클래스 이름이 직관적이지 않음
CSS-in-JS에서는 자동으로 클래스 이름이 생성되는데, 난해한 이름이 될 수 있어 디버깅이 어렵다.

❌ 브라우저에서 스타일을 적용하는 데 시간이 더 걸릴 수 있음
CSS 파일을 미리 읽어오는 전통적인 방식보다, JavaScript가 실행되면서 스타일이 적용되는 방식이기 때문에 성능에 부담이 될 수 있다.

 


런타임 CSS in JS는 런타임에 js파일이 실행되면서 style을 생성한다. style 생성의 규모가 크고 빈번할 수록 성능이 저하된다.

Runtime CSS in JS의 문제점을 해결하기 위해 Zero-runtime CSS in JS가 등장한다. Linaria, Sttiches, Vanilla Extract등이 있다.

 

Vanilla Extract의 특징

  • CSS Modules-inTypeScript
  • 제로 런타임 (Zero-runtime): 기존 CSS-in-JS 라이브러리와 달리, 런타임에 JavaScript로 스타일을 생성하지 않는다. 모든 스타일은 빌드 과정에서 정적 CSS 파일로 추출된다. 이로 인해 런타임 성능이 향상되고 서버 사이드 렌더링(SSR) 시 Hydration 에러를 방지할 수 있다.
  • 타입스크립트 지원 (Type-safe): 스타일을 TypeScript 코드로 작성하므로, CSS 속성 이름이나 값에 대한 오타를 컴파일 시점에 확인할 수 있다. 강력한 타입 추론 및 자동 완성을 제공
  • 로컬 스코프 (Locally Scoped): CSS Modules처럼 기본적으로 클래스 이름에 고유한 해시값을 부여하여 로컬 스코프를 적용. 이로 인해 클래스 이름 충돌을 걱정할 필요가 없다.
  • 표준 CSS와 유사한 작성 방식: JavaScript 객체 형태로 스타일을 정의하지만, 일반적인 CSS 작성 방식과 문법이 매우 유사하여 러닝 커브가 낮다. display: 'flex'처럼 카멜 케이스(camelCase)를 사용
  • 강력한 테마 시스템 (Theming): 타입 안전성이 보장되는 디자인 토큰(CSS 변수)을 활용하여 전역 또는 다중 테마를 쉽게 생성하고 관리
  • 프레임워크 agnostic: 특정 프레임워크에 종속되지 않으며, 웹팩, esbuild, Vite, Next.js 등 다양한 빌드 도구 및 프레임워크와 공식적인 통합을 제공
  • 동적 스타일링 지원 (CSS 변수 활용): props 기반의 동적 스타일링은 어렵지만, CSS 변수(Variables)와 Sprinkles와 같은 유틸리티 API를 통해 동적인 스타일 변화를 지원

Vanilla Extract의 사용법

import { createGlobalTheme, style } from "@vanilla-extract/css";

export const vars = createGlobalTheme(":root", {
    color: {
        main: "#ffa726",
        mainDarker: "#f57c00",
        mainFaded: "#ffb74d",
        mainFadedBright: "#ffb74da6",
        list: "rgb(235, 236, 240)",
        task: "rgb(255, 255, 255)",
        taskHover: "rgb(245, 245, 245)",
        brightText: "rgb(255, 255, 255)",
        darkText: "rgb(24, 42, 77)",
        seconarDdarkText: "rgb(94, 108, 132)",
        seconarDdarkTextHover: "rgb(218, 219, 226)",
        selectedTab: "rgb(137, 176, 174)",
        updateButton: "rgb(237, 180, 88)",
        deleteButton: "rgb(237, 51, 88)",
    },
    fontSizing: {
        T1: "32px",
        T2: "24px",
        T3: "18px",
        T4: "14px",
        P1: "12px",
    },
    spacing: {
        small: "5px",
        medium: "10px",
        big1: "20px",
        big2: "15px",
        listSpacing: "30px"
    },
    font: {
        body: "arial",
    },
    shadow: {
        basic: "4px 4px 8px 0px rgba(34, 60, 80, 0.2)"
    },
    minWidth: {
        list: '250px'
    }
})

 

createGlobalTheme은 vanilla-extract에서 전역 CSS 변수(custom properties)를 정의하는 데 사용되는 핵심 함수.

주로 :root와 같은 전역 셀렉터에 테마 변수를 설정하여 애플리케이션 전체에서 사용할 수 있도록 한다.

:root {
  --color-brand__z05zdf0: blue;
  --color-accent__z05zdf0: honeydew;
  --font-body__z05zdf1: arial;
}

빌드 시 위와 유사한 정적 CSS가 생성된다. 변수 이름은 기본적으로 고유성을 보장하기 위해 해시(예: __z05zdf0)가 추가됨

 

변수 사용법

생성된 vars 객체를 다른 vanilla-extract 스타일시트에서 가져와 타입 안전하게 사용할 수 있다.

import { style } from "@vanilla-extract/css";
import { vars } from "../../App.css";

export const container = style({
    minHeight: 'max-content',
    padding: vars.spacing.big2,
    backgroundColor: vars.color.mainDarker
})