Styling

Cascade Layers (Experimental)

CSS Cascade Layers를 사용하여 SEED 스타일의 우선순위를 제어하는 방법을 알아봅니다.

Tailwind CSS 4 등 CSS Cascade Layer를 사용하는 CSS 프레임워크와 SEED 컴포넌트를 함께 사용할 때, 프레임워크의 유틸리티 클래스로 SEED 컴포넌트 스타일을 오버라이드하려면 다음과 같은 설정이 필요합니다.

  • @layer directive로 래핑된 버전의 SEED CSS 사용
  • 레이어 간 적절한 우선순위 설정

CSS Cascade Layers는 Chrome 99+, Safari 15.4+, Firefox 97+ 이상에서 지원됩니다. (Can I Use)

개요

기본적으로 SEED CSS는 @layer 없이 제공됩니다. 이때 @layer directive 없이 정의된 unlayered 스타일은 layered 스타일보다 항상 높은 우선순위를 갖습니다. (MDN)

/* SEED 컴포넌트 (unlayered) */
/* layered 스타일보다 우선순위를 가짐 */
.seed-floating-action-button__root {
  background: var(--seed-color-bg-brand-solid);
}

/* Tailwind 유틸리티 (layered) */
/* class="seed-floating-action-button__root bg-red-100" 사용 시 SEED 스타일이 우선순위를 가짐 */
@layer utilities {
  .bg-red-100 {
    background-color: var(--color-red-100);
  }
}

이 문제를 해결하기 위해 SEED는 @layer로 래핑된 CSS 파일을 별도로 제공합니다.

설정

base.css 대신 base.layered.css 사용

style.css
@import "@seed-design/css/base.layered.css";

레이어 순서 커스터마이징

seed-baseseed-components 레이어와 다른 레이어의 선언 순서를 적절히 조절합니다.

Tailwind CSS

Tailwind CSS 4 사용 시 유틸리티 클래스를 사용하여 SEED 컴포넌트 스타일을 오버라이드하려면, @layer 선언에서 Tailwind utilities 레이어가 seed-components 레이어보다 높은 우선순위를 가지도록 설정해야 합니다.

@layer theme, base, seed-base, components, seed-components, utilities;

번들러 설정

번들러의 module resolution 설정에 seed-layered condition을 추가하세요. 이 설정을 통해 SEED React 컴포넌트가 내부적으로 CSS를 import할 때, 자동으로 layered 버전을 사용합니다.

vite.config.ts
import { defineConfig } from "vite";

export default defineConfig({
  resolve: {
    conditions: ["seed-layered"], 
  },
  // ...
});

vite.config.ts

Vite conditions 옵션에 대해 알아봅니다.

rsbuild.config.ts
import { defineConfig } from "@rsbuild/core";

export default defineConfig({
  resolve: {
    conditionNames: ["seed-layered", "..."], 
  },
  // ...
});

rsbuild.config.ts

Rsbuild conditionNames 옵션에 대해 알아봅니다.

webpack.config.js
module.exports = {
  resolve: {
    conditionNames: ["seed-layered", "..."], 
  },
  // ...
};

webpack.config.js

Webpack conditionNames 옵션에 대해 알아봅니다.

Chunk Splitting 사용 시 레이어 순서 문제

번들러가 CSS를 여러 청크로 분리하는 경우, @layer seed-components { ... } 블록이 포함된 청크가 다른 @layer 선언보다 먼저 로드되면서 레이어 우선순위가 의도한 것과 달라질 수 있습니다.

HTML에 @layer 선언을 인라인하여 모든 <link> 태그보다 먼저 로드되도록 보장할 수 있습니다.

transformIndexHtml 플러그인 훅으로 <head>의 맨 앞에 <style> 태그를 삽입합니다.

vite.config.ts
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    {
      name: "inject-layer-order",
      transformIndexHtml() {
        return [
          {
            tag: "style", 
            children:
              "@layer theme, base, seed-base, components, seed-components, utilities;", 
            injectTo: "head-prepend", 
          },
        ];
      },
    },
  ],
  // ...
});

html.tags 옵션으로 <head>의 맨 앞에 <style> 태그를 삽입합니다.

rsbuild.config.ts
import { defineConfig } from "@rsbuild/core";

export default defineConfig({
  html: {
    tags: [
      {
        tag: "style", 
        children:
          "@layer theme, base, seed-base, components, seed-components, utilities;", 
        append: false, 
      },
    ],
  },
  // ...
});

HTML 템플릿의 <head> 최상단에 <style> 태그를 추가합니다.

index.html
<head>
  <style>
    @layer theme, base, seed-base, components, seed-components, utilities;
  </style>
</head>

SEED의 레이어 구조

SEED는 두 개의 레이어를 사용합니다.

이름내용파일비고
seed-base디자인 토큰, 글로벌 스타일, keyframesbase.layered.css별도 import 필요
seed-components컴포넌트 스타일recipes/*.layered.cssSEED React 컴포넌트 사용 시 자동 import

관련 문서

Tailwind CSS

Tailwind CSS에서 SEED 토큰을 유틸리티 클래스로 사용하는 방법을 알아봅니다.

Last updated on