Skip to content

Svelte Scoped ​

생성된 CSS를 전역 CSS 파일 대신 각 Svelte 컴포넌트의 <style> 블록에 직접 배치하여 유틸리티 스타일을 제공합니다.

이 컴포넌트:

svelte
<div class="mb-1" />

다음으로 변환됩니다:

svelte
<div class="uno-ei382o" />

<style>
  :global(.uno-ei382o) {
    margin-bottom: 0.25rem;
  }
</style>

언제 사용할까요 ​

사용 사례설명사용할 패키지
작은 앱❌1개의 전역 CSS 파일이 더 편리합니다. Svelte/SvelteKit용 일반 Vite 플러그인을 사용하세요.unocss/vite
큰 앱✅Svelte Scoped는 계속 커지는 전역 CSS 파일을 피하는 데 도움이 됩니다.@unocss/svelte-scoped/vite
컴포넌트 라이브러리✅생성된 스타일이 소비 앱의 빌드 파이프라인에서 UnoCSS를 사용할 필요 없이 빌드된 컴포넌트에 직접 배치됩니다.@unocss/svelte-scoped/preprocess

작동 방식 ​

일반적인 UnoCSS/Tailwind CSS 설정은 유틸리티 스타일을 적절한 순서로 전역 CSS 파일에 배치합니다. 대조적으로 Svelte Scoped는 스타일을 임의로 정렬된 많은 Svelte 컴포넌트 CSS 파일에 분산시킵니다. 그러나 오른쪽에서 왼쪽으로의 텍스트 및 아래 나열된 다른 사용 사례와 같은 것들에 필요한 컨텍스트 인식을 허용하기 위해 유틸리티 스타일을 전역으로 유지해야 합니다. 이는 Svelte의 :global() 래퍼를 사용하여 기본 Svelte CSS 해싱 방법을 선택 해제하고 대신 파일명 + 클래스 이름을 기반으로 한 해시를 사용하여 스타일 충돌 없이 전역으로 만들 수 있는 고유한 클래스 이름을 컴파일하여 해결되는 도전을 제시합니다.

사용법 ​

Svelte Scoped가 유틸리티 클래스 이름을 다시 작성하므로 작성할 수 있는 위치가 제한됩니다:

지원되는 구문예제
Class 속성<div class="mb-1" />
Class 지시문<div class:mb-1={condition} />
Class 지시문 단축<div class:logo />
Class prop<Button class="mb-1" />

Svelte Scoped는 유틸리티 스타일을 사용하는 프로젝트의 드롭인 대체품으로 설계되었습니다. 따라서 클래스 속성 내의 표현식도 지원됩니다 (예: <div class="mb-1 {foo ? 'mr-1' : 'mr-2'}" />) 하지만 앞으로는 클래스 지시문 구문을 사용하는 것을 권장합니다. 또한 <script> 블록에 배치하거나 attributify 모드를 사용하는 것과 같은 다른 방식으로 클래스 이름을 사용한 경우 Svelte Scoped를 사용하기 전에 추가 단계가 필요합니다. safelist 옵션을 활용할 수 있고 아래 presets 섹션에서 더 많은 팁을 확인할 수 있습니다.

컨텍스트 인식 ​

스타일이 앱의 Svelte 컴포넌트에 분산되어 있지만 여전히 전역 클래스이며 특정 컴포넌트 외부에서 찾은 요소와의 관계에서 작동합니다. 몇 가지 예시가 있습니다:

부모 의존 ​

부모 컴포넌트에서 찾은 속성에 의존하는 클래스:

svelte
<div class="dark:mb-2 rtl:right-0"></div>

다음으로 변환됩니다:

svelte
<div class="uno-3hashz"></div>

<style>
  :global(.dark .uno-3hashz) {
    margin-bottom: 0.5rem;
  }
  :global([dir="rtl"] .uno-3hashz) {
    right: 0rem;
  }
</style>

자식 영향 ​

일부가 별도 컴포넌트에 있는 3개의 자식 요소 사이에 공간을 추가할 수 있습니다:

svelte
<div class="space-x-1">
  <div>Status: online</div>
  <Button>FAQ</Button>
  <Button>Login</Button>
</div>

다음으로 변환됩니다:

svelte
<div class="uno-7haszz">
  <div>Status: online</div>
  <Button>FAQ</Button>
  <Button>Login</Button>
</div>

<style>
  :global(.uno-7haszz > :not([hidden]) ~ :not([hidden])) {
    --un-space-x-reverse: 0;
    margin-left: calc(0.25rem * calc(1 - var(--un-space-x-reverse)));
    margin-right: calc(0.25rem * var(--un-space-x-reverse));
  }
</style>

자식 컴포넌트에 클래스 전달 ​

컴포넌트가 소비되는 곳에서 사용자 정의 클래스를 전달할 수 있도록 class prop을 컴포넌트에 추가할 수 있습니다.

svelte
<Button class="px-2 py-1">Login</Button>

다음으로 변환됩니다:

svelte
<Button class="uno-4hshza">Login</Button>

<style>
  :global(.uno-4hshza) {
    padding-left:0.5rem;
    padding-right:0.5rem;
    padding-top:0.25rem;
    padding-bottom:0.25rem;
  }
</style>

수신 컴포넌트에서 클래스를 구현하는 쉬운 방법은 div class="{$$props.class} foo bar" />와 같이 {$$props.class}를 사용하여 요소에 배치하는 것입니다.

Apply 지시문 ​

--at-apply 또는 @apply 또는 applyVariables 옵션을 사용하여 설정한 사용자 정의 값을 사용하여 <style> 블록 내에서 apply 지시문을 사용할 수 있습니다.

Svelte Scoped는 Svelte 스타일 블록을 위해 특별히 구축되지 않았기 때문에 일반 @unocss/transformer-directives 패키지가 제대로 처리할 수 없는 dark:text-white와 같은 컨텍스트 의존 클래스도 제대로 처리합니다. 예를 들어, Svelte Scoped를 사용하면 이 컴포넌트:

svelte
<div />

<style>
  div {
    --at-apply: rtl:ml-2;
  }
</style>

다음으로 변환됩니다:

svelte
<div />

<style>
  :global([dir=\\"rtl\\"]) div {
    margin-right: 0.5rem;
  }
</style>

rtl:ml-2가 제대로 작동하려면 [dir="rtl"] 선택자가 :global()로 래핑되어 컴포넌트에 해당 속성을 가진 요소가 없기 때문에 Svelte 컴파일러가 자동으로 제거하지 않도록 합니다. 그러나 div는 :global() 래퍼에 포함될 수 없습니다. 그렇게 하면 해당 스타일이 앱의 모든 div에 영향을 미치기 때문입니다.

기타 스타일 블록 지시문 ​

theme() 사용도 지원되지만 @screen은 지원되지 않습니다.

Vite Plugin ​

Svelte 또는 SvelteKit 앱에서 생성된 스타일을 Svelte 컴포넌트에 직접 주입하면서 최소한의 필요한 스타일을 전역 스타일시트에 배치합니다. Stackblitz의 SvelteKit 예제를 확인하세요:

Open in StackBlitz

설치 ​

bash
pnpm add -D unocss @unocss/svelte-scoped
bash
yarn add -D unocss @unocss/svelte-scoped
bash
npm install -D unocss @unocss/svelte-scoped
bash
bun add -D unocss @unocss/svelte-scoped

플러그인 추가 ​

Vite 설정에 @unocss/svelte-scoped/vite를 추가하세요:

ts
import { sveltekit } from '@sveltejs/kit/vite'
import UnoCSS from '@unocss/svelte-scoped/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    UnoCSS({
      // injectReset: '@unocss/reset/normalize.css', // see type definition for all included reset options or how to pass in your own
      // ...other Svelte Scoped options
    }),
    sveltekit(),
  ],
})

설정 파일 추가 ​

아래 설정에 설명된 대로 uno.config.ts 파일을 설정하세요.

전역 스타일 ​

거의 모든 스타일이 개별 컴포넌트에 배치되지만 여전히 전역 스타일시트에 배치해야 하는 몇 가지가 있습니다: preflight, safelist, 그리고 선택적 리셋 (injectReset 옵션을 사용하는 경우).

<head> 태그에 %unocss-svelte-scoped.global% 플레이스홀더를 추가하세요. Svelte에서는 index.html입니다. SvelteKit에서는 %sveltekit.head% 앞의 app.html에 있습니다:

html
<head>
  <!-- ... -->
  <title>SvelteKit using UnoCSS Svelte Scoped</title>
  %unocss-svelte-scoped.global%
  %sveltekit.head%
</head>

SvelteKit을 사용하는 경우 src/hooks.server.js 파일의 transformPageChunk 훅에 다음을 추가해야 합니다:

js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
  const response = await resolve(event, {
    transformPageChunk: ({ html }) =>
      html.replace(
        '%unocss-svelte-scoped.global%',
        'unocss_svelte_scoped_global_styles'
      ),
  })
  return response
}

일반 Svelte 프로젝트에서 Vite의 transformIndexHtml 훅이 이를 자동으로 수행합니다.

Svelte Preprocessor ​

전처리기를 사용하여 생성된 스타일을 빌드된 컴포넌트에 직접 배치하여 동반 CSS 파일을 포함할 필요가 없는 컴포넌트 라이브러리를 구축하기 위해 유틸리티 스타일을 사용하세요. Stackblitz의 SvelteKit Library 예제를 확인하세요:

Open in StackBlitz

설치 ​

bash
pnpm add -D unocss @unocss/svelte-scoped
bash
yarn add -D unocss @unocss/svelte-scoped
bash
npm install -D unocss @unocss/svelte-scoped
bash
bun add -D unocss @unocss/svelte-scoped

전처리기 추가 ​

Svelte 설정에 @unocss/svelte-scoped/preprocess를 추가하세요:

ts
import adapter from '@sveltejs/adapter-auto'
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import UnoCSS from '@unocss/svelte-scoped/preprocess'

const config = {
  preprocess: [
    vitePreprocess(),
    UnoCSS({
      // ... preprocessor options
    }),
  ],
  // other Svelte config
}

개발에서 클래스 이름 결합하지 않기 ​

일반 앱에서 Svelte Scoped를 사용할 때 Vite 플러그인이 자동으로 dev와 build를 감지합니다. 개발에서는 클래스가 구별되고 브라우저의 개발자 도구에서 쉽게 켜고 끌 수 있도록 제자리에서 해시됩니다. class="mb-1 mr-1"은 class="_mb-1_9hwi32 _mr-1_84jfy4와 같은 것으로 변환됩니다. 프로덕션에서는 원하는 접두사(기본값 uno-)와 파일명 + 클래스 이름을 기반으로 한 해시를 사용하여 단일 클래스 이름으로 컴파일됩니다. 예: class="uno-84dke3.

전처리기를 사용할 때 동일한 동작을 원한다면 환경에 따라 combine 옵션을 수동으로 설정해야 합니다. 한 가지 방법은 cross-env를 설치하고 개발 스크립트를 다음과 같이 업데이트하는 것입니다:

"dev": "cross-env NODE_ENV=development vite dev"

그런 다음 svelte.config.js를 조정하세요:

diff
+const prod = process.env.NODE_ENV !== 'development'
const config = {
  preprocess: [
    vitePreprocess(),
    UnoCSS({
+      combine: prod,
    }),
  ],
}

설정 파일 추가 ​

아래 설정에 설명된 대로 uno.config.ts 파일을 설정하세요.

Preflight ​

전처리기를 사용할 때 필요한 특정 컴포넌트에 preflight을 포함할 수 있는 옵션이 있습니다. uno-preflights를 스타일 속성으로 추가하세요.

html
<style uno-preflights></style>

.prose :where(a):not(:where(.not-prose, .not-prose *))와 같이 마침표로 시작하는 특별한 preflight은 Svelte 컴파일러에 의해 자동으로 제거되지 않도록 :global()로 래핑됩니다.

클래스가 preflight에 의존하지 않거나 빌드된 컴포넌트가 이미 preflight을 포함하는 앱에서만 소비되는 경우 개별 컴포넌트에 preflight을 추가하는 것은 불필요합니다.

Safelist ​

전처리기를 사용할 때 uno-safelist를 스타일 속성으로 추가하여 컴포넌트에 safelist 클래스를 포함할 수 있는 옵션이 있습니다.

html
<style uno-safelist></style>

Safelist 스타일은 Svelte 컴파일러에 의해 자동으로 제거되지 않도록 :global()로 래핑됩니다.

설정 ​

UnoCSS 설정을 uno.config.ts 파일에 배치하세요:

ts
import { defineConfig } from 'unocss'

export default defineConfig({
  // ...UnoCSS options
})

일반 UnoCSS 전역 사용과 Svelte Scoped 사용의 차이로 인해 추출기는 지원되지 않습니다. Preset과 Transformer는 다음 섹션에서 설명한 대로 지원됩니다. 다른 모든 세부사항은 Config File과 Config reference를 참조하세요.

Preset 지원 ​

전역 스타일시트에 몇 가지 필요한 스타일이 있고 나머지는 필요한 각 컴포넌트에 포함되는 특성으로 인해 preset은 사례별로 처리해야 합니다:

Preset지원됨참고사항
@unocss/preset-uno, @unocss/preset-mini, @unocss/preset-wind3, @unocss/preset-icons, @unocss/web-fonts✅이들과 unocss-preset-forms와 같은 모든 커뮤니티 플러그인은 규칙/variant/preflight에만 의존하는 경우 작동합니다.
@unocss/preset-typography✅이 preset이 preflight에 규칙 세트를 추가하는 방식으로 인해 이 preset을 사용할 때 prose 클래스를 safelist에 추가해야 합니다. 그렇지 않으면 preflight이 트리거되지 않습니다. 이 preset의 다른 모든 클래스(예: prose-pink)는 컴포넌트 스코프를 가질 수 있습니다.
@unocss/preset-rem-to-px✅이것과 스타일 출력만 수정하는 모든 preset이 작동합니다.
@unocss/preset-attributify-Preset이 작동하지 않습니다. 대신 Svelte Scoped Vite 플러그인보다 먼저 unplugin-attributify-to-class Vite 플러그인 (attributifyToClass({ include: [/\.svelte$/]}))을 사용하세요
@unocss/preset-tagify-사용자 정의 추출기를 추가하는 preset은 작동하지 않습니다. <text-red>Hi</text-red>를 <span class="text-red">Hi</span>로 변환하는 전처리기를 만들고 링크를 여기에 추가하기 위해 PR을 만드세요.

다른 preset의 경우 전통적인 class="..." 사용에 의존하지 않는다면 먼저 해당 클래스 이름을 class="..." 속성으로 전처리해야 합니다. Typography의 .prose 클래스와 같은 preset을 추가한다면 preset 추가를 트리거하는 클래스를 safelist에 배치해야 합니다.

Transformer 지원 ​

CSS 파일(css|postcss|sass|scss|less|stylus|styl)에 대한 Transformer가 지원됩니다. 사용하려면 vite.config.ts의 cssFileTransformers 옵션에 transformer를 추가하세요:

ts
import transformerDirectives from '@unocss/transformer-directives'

export default defineConfig({
  plugins: [
    UnoCSS({
      cssFileTransformers: [transformerDirectives()],
    }),
    sveltekit(),
  ],
})

INFO

Svelte Scoped의 작동 방식으로 인해 Svelte 컴포넌트에서는 Transformer가 지원되지 않습니다.

스코프 유틸리티 클래스가 창의성을 해방합니다 ​

스코프 스타일을 사용하고 싶을 때에 대한 조언: 큰 프로젝트의 생명에서 .md:max-w-[50vw]와 같은 클래스를 사용할 때마다 전역 스타일시트의 크기가 점점 커지는 것을 느끼며 움찔할 정도가 되었다면 이 패키지를 시도해보세요. 정확히 필요한 클래스를 사용하는 것을 망설이는 것은 창의성을 억제합니다. 물론 스타일 블록에서 --at-apply: md:max-w-[50vw]를 사용할 수 있지만 그것은 지루해지고 컨텍스트의 스타일이 유용합니다. 또한 프로젝트에 다양한 아이콘을 포함하고 싶다면 전역 스타일시트에 추가하는 것의 무게를 느끼기 시작할 것입니다. 각 컴포넌트가 자체 스타일과 아이콘의 무게를 지게 되면 각 새로운 추가의 비용 혜택을 분석할 필요 없이 프로젝트를 계속 확장할 수 있습니다.

라이선스 ​

Released under the MIT License.