NextJs CSS-in-JS 라이브러리 추천 pandaCSS

EN

원문: Medium에서 보기 Medium 글을 이 블로그로 이관한 버전입니다.

PandaCSS: 왜 우리는 이 CSS-in-JS 라이브러리를 선택했는가?

들어가며

SSR이 등장하고 서버 우선 프레임워크가 등장하면서 대부분의 CSS-in-JS 라이브러리가 안정적으로 작동하지 않거나 작동하지 않을 수 있습니다. 저도 styled-components를 사용하면서 성능이 떨어지는 경험을 했습니다. 이러한 한계를 느끼고 많이 사용하는 정적 클래스 생성기인 Tailwind CSS 프레임워크를 고려했지만, 전처리된 클래스 명을 학습해야 하는 러닝 커브가 있었습니다.

반면에, 같은 CSS-in-JS인 PandaCSS는 스타일 생성이 빌드 타임에 이뤄지기 때문에 런타임 스타일 생성 오버헤드가 거의 없습니다.

프로젝트 빌드 시 styled-system 디렉터리를 미리 생성하고, 자주 사용하는 스타일 패턴을 클래스 형태로 만들어 두기 때문입니다. 그래서 컴포넌트 코드에서는 조건에 따라 클래스를 조합해 유연하게 스타일링할 수 있으면서도, 스타일 생성 비용 자체는 런타임에 거의 들지 않습니다.

하지만 PandaCSS도 몇 가지 단점이 있습니다. 예를 들어, 생성되는 클래스 이름이 길어 E2E 테스트나 마케팅 용도로 Google Analytics를 사용할 때 불편할 수 있습니다. Tailwind CSS와 같은 다른 라이브러리에서도 발생하는 문제입니다.

이러한 단점에도 불구하고 PandaCSS를 사용하기로 결정했습니다. 그리고 기술 스택을 선정할때 모든 팀원들을 고려를 해야했습니다. styled-components 를 사용했기 때문에 PandaCSS의 style-function 방식을 차용하기로 했습니다.

PandaCSS의 장점

  1. 타입 안전성 제공: PandaCSS는 타입스크립트와 깊이 통합되어 있으며, 이를 통해 타입 안전성을 제공합니다. 스타일 작성 중 발생할 수 있는 오류를 조기에 발견할 수 있어 유지 보수성이 크게 향상됩니다​​.
  2. 빌드 타임 스타일 생성: 런타임이 아닌 빌드 타임에 CSS를 생성하기 때문에 런타임 오버헤드가 전혀 없습니다. 이를 통해 페이지 로딩 속도를 빠르게 하고, 번들 크기를 줄일 수 있습니다​​.
  3. 다양한 프레임워크와 호환: Next.js, Remix, Vite 등 다양한 최신 자바스크립트 프레임워크와 호환되며, 서버사이드 렌더링 환경에서도 문제없이 작동합니다​.
  4. 유틸리티 우선 접근 방식: PandaCSS는 작은 단위의 유틸리티 클래스를 사용하여 복잡한 스타일을 쉽게 구성할 수 있습니다. 이는 코드의 가독성과 유지 보수성을 높이며, Tailwind CSS와 같은 프레임워크의 장점을 취하면서도 런타임 오버헤드를 제거할 수 있습니다​.

PandaCSS 설정 및 사용법

panda.config.ts 설정 파일

PandaCSS는 설정 파일인 panda.config.ts를 통해 스타일 시스템을 구성합니다. 이 파일에서 스타일 시트의 출력 디렉토리, 테마 확장, 포함할 파일 등을 정의할 수 있습니다.

import { defineConfig } from '@pandacss/dev';
import { textStyles } from './theme/textStyle';

export default defineConfig({
  preflight: true, // 기본 스타일 재설정 여부
  include: ['./src/**/*.{js,jsx,ts,tsx}', './pages/**/*.{js,jsx,ts,tsx}'],
  exclude: [],
  theme: {
    extend: {
      textStyles,
    },
  },
  outdir: 'styled-system',
});

PandaCSS 레이어 규칙

globals.css를 프로젝트에 import하여 스타일링의 우선순위를 정할 수 있으며, 각 레이어는 필요에 따라 스타일을 오버라이드합니다.

PandaCSS는 CSS 스타일링을 좀 더 구조적으로 관리하기 위해 “레이어 규칙(Layer Rules)”을 사용합니다. 이러한 레이어 규칙을 통해 스타일의 우선순위를 명확히 하고, 스타일 적용의 유연성을 높입니다. 각 레이어는 서로 다른 역할을 가집니다.

@layer reset, base, tokens, recipes, utilities;
  • reset: HTML 기본 스타일을 재설정합니다.
  • base: 글로벌 스타일을 포함합니다.
  • tokens: 시맨틱 토큰 및 디자인 토큰을 포함합니다.
  • recipes: 컴포넌트 스타일을 포함합니다.
  • utilities: 유틸리티 클래스 스타일을 포함합니다.

자세한 레이어에 대한 것은 다음 시리즈에 포스팅 하겠습니다 :)

예제 코드

아래의 코드는 PandaCSS의 css 함수를 사용하여 스타일을 작성하는 예시입니다. 이 함수는 스타일 객체를 받아 className 문자열을 반환합니다.

import { css } from '../styled-system/css';

const styles = css({
  backgroundColor: 'gainsboro',
  borderRadius: '9999px',
  fontSize: '13px',
  padding: '10px 15px'
});

<div className={styles}>
  <p>Hello World</p>
</div>

PandaCSS는 스타일 속성을 단축어로 사용하고, 타입스크립트와 통합하여 안전하고 효율적인 코드 작성을 도와줍니다. 또한, 최신 CSS 기능을 활용하여 코드의 유지 보수성과 재사용성을 높입니다.

결론

PandaCSS는 런타임 오버헤드를 줄이고, 효율적인 스타일 관리 및 유지 보수를 가능하게 하는 강력한 CSS-in-JS 라이브러리입니다. 다양한 프레임워크와의 호환성이 뛰어나며, 서버사이드 렌더링 환경에서도 성능 문제가 없습니다. 성능 문제를 해결하고자 하는 분들에게는 훌륭한 선택이 될 수 있습니다.

지난 6개월 동안 사용하면서 아직까지 정식 버전은 출시되지 않았지만, 프로덕션 레벨에서 사용하기에 불편함이 없습니다. 또한, 매달 활발히 업데이트되고 있는 라이브러리입니다. 사실 이제 더 이상 CSS 라이브러리에 대한 고민은 던져버리고, 다른 고차원적인 문제 해결에 에너지를 쓰는 것이 더 유용하다고 생각합니다. 따라서 CSS라이브러리를 사용한다고 하면 무엇보다 쉽고-범용적인 라이브러리를 추천합니다.

더 자세한 정보와 예제는 PandaCSS 공식 사이트에서 확인할 수 있습니다.