향기로운 스타일링

전준연·2025년 3월 24일
post-thumbnail

목적

이번에 동아리 친구들과 함께 프로젝트를 진행하게 되었는데, Next.js를 사용하여 개발하기로 결정했다. 기획 단계에서 스타일링 방식에 대해 논의하게 되었는데, 두 가지 의견이 나왔다. 하나는 Next.js에서 권장하는 Tailwind를 사용하자는 것이었고, 다른 하나는 우리가 가장 익숙한 styled-components(또는 Emotion)를 사용하는 것이었다.

하지만 고민할 점이 몇 가지 있었다. Tailwind는 프론트엔드 팀원 3명 중 2명이 사용 경험은 있지만 익숙하지 않아서 개발 속도가 늦어질 가능성이 있었다. 반면, styled-components는 런타임 CSS-in-JS 라이브러리이기 때문에, 로직이 들어가지 않는 페이지라 하더라도 클라이언트 컴포넌트로 사용해야 한다는 점이 걸렸다. 그렇게 되면 Next.js의 서버 컴포넌트의 장점을 충분히 활용하지 못할 것 같았다.

그러던 중, 선배님의 블로그에서 vanilla-extract라는 빌드 타임 CSS-in-JS 라이브러리를 알게 되었다. 사용법을 살펴보니 styled-components와 비슷한 방식으로 활용할 수 있었고, 빌드 타임에 스타일이 생성되기 때문에 성능적인 이점도 있었다. 친구들과 논의 끝에 vanilla-extract를 사용하기로 결정했고, 이 글에서는 해당 라이브러리에 대한 간단한 소개와 사용 후기를 정리해보려고 한다.

바닐라 추출물?

vanilla-extract를 검색해보면 요리에서 사용하는 바닐라 추출물이 먼저 뜬다. 하지만 이번에 살펴볼 vanilla-extract는 빌드 타임 CSS-in-JS 라이브러리다. 본격적으로 사용법을 알아보기 전에, 먼저 CSS-in-JS가 왜 대세인지, 그리고 런타임 CSS-in-JS와 빌드 타임 CSS-in-JS의 차이점에 대해 알아보자.

CSS-in-JS가 대세인 이유

CSS-in-JS가 널리 사용되는 주요 이유는 다음과 같다.

  1. 클래스 이름 중복을 신경 쓸 필요 없음

    • 전역 스타일 충돌을 방지할 수 있어 유지보수가 쉬워진다.
  2. JS 코드와 CSS가 상태 값을 공유할 수 있음

    • 컴포넌트의 상태에 따라 동적으로 스타일을 변경할 수 있다.
  3. 컴포넌트와 스타일 코드를 쉽게 오갈 수 있음

    • 스타일을 컴포넌트 단위로 관리할 수 있어 코드의 가독성과 관리성이 향상된다.

이러한 이유들로 인해 CSS-in-JS는 개발자 경험(DX, Developer Experience)을 개선하는 방식으로 인식되며, 최근 많이 사용되고 있다. 그렇다면 런타임 CSS-in-JS와 빌드 타임 CSS-in-JS는 어떤 차이가 있을까?

런타임 CSS-in-JS

말 그대로 JS 런타임에서 필요한 CSS를 동적으로 생성하여 적용하는 방식이다. 대표적인 라이브러리로는 styled-componentsEmotion이 있다.

장점

  • 스타일의 재사용성이 높다.

  • JS 변수를 활용한 동적 스타일링이 가능하다.

단점

  • 빌드 타임 CSS-in-JS에 비해 성능이 떨어질 수 있음.

  • 번들 크기가 증가할 가능성이 있음.

빌드 타임 CSS-in-JS

빌드 시점에 CSS를 생성하여 런타임에서는 CSS를 추가적으로 처리할 필요가 없는 방식이다. 따라서 페이지 로딩 속도가 더 빠르다. 대표적인 라이브러리로는 vanilla-extractTailwind가 있다.

장점

  • 런타임 성능 최적화.

  • SSR(서버 사이드 렌더링) 최적화.

단점

  • 빌드 속도가 증가할 수 있음.

  • 동적 스타일 적용이 어려움.

이제 CSS-in-JS의 흐름과 방식에 대한 이해가 어느 정도 되었을 거라고 생각한다. 다음으로, 오늘의 주인공인 vanilla-extract를 어떻게 사용하는지를 알아보자.

사용

설치

NPM

npm install @vanilla-extract/css

Yarn

yarn add @vanilla-extract/css

PNPM

pnpm add @vanilla-extract/css

파일 컨벤션

vanilla-extract에서는 스타일 파일의 확장자를 [파일이름].css.ts 또는 [파일이름].css.js로 지정해야 한다.

기본 코드

vanilla-extract의 가장 기본적인 문법인 style은 styled-components의 styled와 유사한 방식으로 사용된다.

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

export const Container = style({
  display: 'flex',
  backgroundColor: 'white',
  color: 'red',
});
// index.tsx
import * as S from './style.css';

const Page = () => {
  return <div className={S.Container}>Hello, world!</div>;
};

export default Page;

특징

vanilla-extract는 기존에 사용하던 styled-components나 Emotion과 비교했을 때 몇 가지 차이점이 있다.

  1. 기본 단위

    • CSS 속성 값에 단위를 명시하지 않으면 기본적으로 px 단위가 적용된다.
    export const Box = style({
    	width: 100, // 100px로 자동 변환
    	height: 50, // 50px로 자동 변환
    });
    
  2. camelCase 사용

    • CSS 속성들을 camelCase로 작성해야 한다.
    export const TextStyle = style({
    	fontSize: 16, // font-size -> fontSize
    	backgroundColor: 'blue', // background-color -> backgroundColor
    });
    
  3. className 사용

    • module.css와 유사하게 스타일을 className 속성으로 적용해야 한다.
    <div className={S.Container}>Hello, world!</div>

마무리

오늘은 프로젝트를 진행하면서 처음으로 사용해본 vanilla-extract를 정리해 보았다. 사용 자체에는 큰 문제가 없었지만, 다음에 스타일링 라이브러리를 선택해야 한다면 그냥 Tailwind를 사용할 것 같다.

가장 큰 이유는 초기 설정의 차이였다. Tailwind는 Next.js 프로젝트를 생성할 때 자동으로 초기 세팅까지 지원해 주지만, vanilla-extract는 직접 설정을 추가해야 해서 다소 시간이 걸렸다.

또한, 자료나 사용 예시도 Tailwind가 압도적으로 많았다. vanilla-extract는 상대적으로 정보가 적어서, 문제 해결 시 시간이 더 소요될 가능성이 있었다.

이번 기회에 Tailwind에도 익숙해지는 것이 좋을 것 같다는 생각이 들었다. 다음 프로젝트에서는 Tailwind를 활용해보며 적응해봐야겠다.

0개의 댓글