Vanilla extract 통합

Vanilla extract 통합

Vanilla extract는 빌드 시점에 정적 CSS 파일을 생성하는 TypeScript CSS 전처리기예요. 스타일을 TypeScript로 작성하는 것을 선호한다면 CSS Modules의 훌륭한 대안이에요.

출처: 문서

본문

Vanilla extract vs CSS Modules

Vanilla extract와 CSS Modules은 같은 일을 하지만 문법이 달라요. Vanilla extract와 CSS Modules의 공통 기능:

  • 스타일이 빌드 시점에 생성돼요 – 런타임과 성능 오버헤드가 없어요

  • 클래스 이름이 스타일 파일로 스코프돼요

Vanilla extract와 CSS Modules의 차이점:

  • Vanilla extract 스타일은 타입 안전(type-safe)해요

  • Vanilla extract 스타일에서 색상 함수를 포함한 어떤 JavaScript/TypeScript 코드든 사용할 수 있어요

  • Vanilla extract에서는 light-dark 함수와 hover 믹스인 같은 postcss-preset-mantine 기능에 접근할 수 없어요. 이 때문에 Mantine 문서의 모든 데모를 복사-붙여넣기해서 Vanilla extract와 함께 쓸 수는 없어요.

  • Vanilla extract는 빌드 도구/프레임워크에서 사용할 수 없는 추가 구성과 설정이 필요해요. Next.js와 Vite 같은 가장 인기 있는 도구는 Vanilla extract 플러그인을 가지지만, 더 틈새적인 것을 사용한다면 직접 구성해야 할 수도 있어요.

같은 프로젝트에서 Vanilla extract와 CSS Modules을 둘 다 사용할 수 있다는 점에 주의하세요; 문제가 발생하지 않아요: 성능은 같고 번들 크기도 영향받지 않아요.

설치

설치 안내를 따라 Vanilla extract를 설치해요. 그런 다음 @mantine/vanilla-extract 패키지를 설치해요; 이 패키지는 Mantine theme을 CSS variables로 변환하는 themeToVars 함수를 내보내요:

yarn add @mantine/vanilla-extract

템플릿

시작하려면 다음 템플릿 중 하나를 사용하거나 자신의 설정을 위한 참고 자료로 삼을 수 있어요. 모든 템플릿은 최소한의 설정만 포함한다는 점에 주의하세요.

템플릿 설명 링크
next-vanilla-extract-template Vanilla extract 예시가 있는 Next.js 템플릿 Use template
vite-vanilla-extract-template Vanilla extract 예시가 있는 Vite 템플릿 Use template

Theming

Vanilla extract는 주어진 theme 객체를 CSS variables로 변환하고 :root 또는 다른 selector에 할당하는 createTheme 함수를 제공해요. Mantine theme 토큰을 생성하는 데 Vanilla extract의 createTheme를 사용하지 마세요 – 모든 Mantine theme 속성은 이미 CSS variables로 노출돼 있어요. 대신 @mantine/vanilla-extract 패키지의 themeToVars 함수를 사용해 Mantine theme에서 CSS variables 객체를 만들어요:

// theme.ts
import { createTheme } from '@mantine/core';

// Do not forget to pass theme to MantineProvider
export const theme = createTheme({
  fontFamily: 'serif',
  primaryColor: 'cyan',
});
// theme.css.ts
import { theme } from './theme';
import { themeToVars } from '@mantine/vanilla-extract';

// CSS variables object, can be access in *.css.ts files
export const vars = themeToVars(theme);

스타일링

*.css.ts 파일에서 vars 객체를 import 해 Mantine CSS variables에 접근해요:

// Demo.css.ts
import { style } from '@vanilla-extract/css';
import { vars } from './theme';

export const demo = style({
  fontSize: vars.fontSizes.xl,
  backgroundColor: vars.colors.red[5],
  color: vars.colors.white,
});

rem과 em

px를 rem 또는 em으로 변환하려면 @mantine/core 패키지의 rem과 em 함수를 사용해요:

// Demo.css.ts
import { style } from '@vanilla-extract/css';
import { rem } from '@mantine/core';

export const demo = style({
  fontSize: rem(16),

  '@media': {
    [`(min-width: ${em(768)})`]: {
      fontSize: rem(18),
    },
  },
});

light와 dark selectors

vars 객체에는 light 또는 dark 색상 체계에서만 스타일을 적용하는 데 사용할 수 있는 lightSelector와 darkSelector 속성이 있어요:

// Demo.css.ts
import { style } from '@vanilla-extract/css';
import { vars } from './theme';

export const demo = style({
  fontSize: vars.fontSizes.xl,

  selectors: {
    [vars.lightSelector]: {
      backgroundColor: vars.colors.red[5],
      color: vars.colors.white,
    },

    [vars.darkSelector]: {
      backgroundColor: vars.colors.blue[5],
      color: vars.colors.white,
    },
  },
});

보통 둘 중 하나만 사용하는 것이 더 편리해요: light 색상 체계의 스타일을 적용한 다음 vars.darkSelector(또는 그 반대)로 dark 색상 체계에서 재정의해요:

// Demo.css.ts
import { style } from '@vanilla-extract/css';
import { vars } from './theme';

export const demo = style({
  fontSize: vars.fontSizes.xl,
  backgroundColor: vars.colors.red[5],
  color: vars.colors.white,

  selectors: {
    [vars.darkSelector]: {
      backgroundColor: vars.colors.blue[5],
      color: vars.colors.white,
    },
  },
});

largerThan과 smallerThan

vars 객체에는 @media에서 min-width와 max-width의 축약형으로 사용할 수 있는 largerThan과 smallerThan 속성이 있어요:

// Demo.css.ts
import { style } from '@vanilla-extract/css';
import { vars } from './theme';

export const demo = style({
  fontSize: vars.fontSizes.sm,

  '@media': {
    // equivalent to `(min-width: 640px)` converted to em
    // -> `(min-width: 40em)`
    [vars.largerThan(640)]: {
      fontSize: vars.fontSizes.md,
    },

    // equivalent to `(max-width: 640px)` converted to em
    // -> `(max-width: 40em)`
    [vars.smallerThan(640)]: {
      fontSize: vars.fontSizes.xs,
    },

    // You can reference `theme.breakpoints` values
    [vars.largerThan('sm')]: {
      fontSize: vars.fontSizes.md,
    },
  },
});

rtl selector

vars.rtlSelector를 사용해 rtl 방향에서만 스타일을 적용해요:

// Demo.css.ts
import { style } from '@vanilla-extract/css';
import { vars } from './theme';

export const demo = style({
  paddingRight: vars.spacing.md,

  selectors: {
    [vars.rtlSelector]: {
      paddingLeft: vars.spacing.md,
      paddingRight: 0,
    },
  },
});

더 알아보기 (Learn more)