Skip to content

Svelte Scoped

Plasează CSS-ul generat pentru stilurile utilitare ale fiecărei componente Svelte direct în blocul <style> al componentei Svelte, în loc să-l pui într-un fișier CSS global.

Această componentă:

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

se transformă în:

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

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

Când să folosești

Use CaseDescriptionPackage to Use
Smaller appsHaving 1 global CSS file is more convenient. Use the regular Vite plugin for Svelte/SvelteKit.unocss/vite
Larger appsSvelte Scoped can help you avoid an ever-growing global CSS file.@unocss/svelte-scoped/vite
Component libraryGenerated styles are placed directly in built components without the need to use UnoCSS in a consuming app's build pipeline.@unocss/svelte-scoped/preprocess

Cum funcționează

O configurație obișnuită UnoCSS/Tailwind CSS plasează stilurile utilitare într-un fișier CSS global, cu o ordine corespunzătoare. În contrast, Svelte Scoped distribuie stilurile tale în mai multe fișiere CSS de componente Svelte, ordonate arbitrar. Totuși, trebuie să păstreze stilurile utilitare globale pentru a le permite să fie conștiente de context, așa cum este necesar pentru lucruri precum right-to-left și alte cazuri de utilizare enumerate mai jos. Aceasta prezintă o provocare care este rezolvată prin utilizarea wrapper-ului :global() al Svelte pentru a renunța la metoda implicită de hash CSS a Svelte și, în schimb, să folosească un hash bazat pe numele fișierului + numele clasei(claselor) pentru a compila nume de clase unice care pot fi făcute globale fără conflicte de stil.

Utilizare

Deoarece Svelte Scoped reescrie numele claselor utilitare, vă este limitat în unde puteți scrie-le:

Sintaxă suportatăExemplu
Atribut de clasă<div class="mb-1" />
Direcție de clasă<div class:mb-1={condition} />
Direcție de clasă scurtă<div class:logo />
Proprietate de clasă<Button class="mb-1" />

Svelte Scoped este conceput pentru a fi un înlocuitor direct pentru proiectele care folosesc stiluri utilitare. Ca atare, expresiile găsite în atributele de clasă sunt, de asemenea, acceptate (de exemplu, <div class="mb-1 {foo ? 'mr-1' : 'mr-2'}" />), dar vă recomandăm să folosiți sintaxa directivelor de clasă pe viitor. De asemenea, rețineți că, dacă ați folosit nume de clasă în alte moduri, cum ar fi plasarea lor într-un bloc <script> sau utilizarea modului de atributificare, va trebui să faceți pași suplimentari înainte de a folosi Svelte Scoped. Puteți utiliza opțiunea safelist și puteți verifica secțiunea presets de mai jos pentru mai multe sfaturi.

Context aware

Deși stilurile sunt distribuite pe baza componentelor Svelte ale aplicației, acestea încă sunt clase globale și vor funcționa în relație cu elementele găsite în afara componentelor specificate. Aici sunt câteva exemple:

Parent dependent

Clasele care depind de atribute găsite într-o componentă părinte:

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

se transformă în:

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

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

Influențarea copiilor

Puteți adăuga spațiu între 3 elemente copil care sunt într-o componentă separată:

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

se transformă în:

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>

Transmiterea claselor către componentele copil

Puteți adăuga o proprietate class într-o componentă pentru a permite transmiterea claselor personalizate în orice loc unde componenta este utilizată.

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

se transformă în:

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>

O metodă ușoară de a implementa clasa în componenta primitoare ar fi să le plasați pe un element utilizând {$$props.class} ca în div class="{$$props.class} foo bar" />.

Aplicați directiva

Puteți utiliza directiva apply într-un bloc <style> cu --at-apply sau @apply sau o valoare personalizată setată utilizând opțiunea applyVariables.

Svelte Scoped gestionează chiar și clasele dependente de context precum dark:text-white pe care pachetul obișnuit @unocss/transformer-directives nu le poate trata corespunzător, deoarece nu a fost construit special pentru blocurile de stiluri Svelte. De exemplu, cu Svelte Scoped această componentă:

svelte
<div />

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

se transformă în:

svelte
<div />

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

Pentru ca rtl:ml-2 să funcționeze corect, selectorul [dir="rtl"] este înfășurat cu :global() pentru a împiedica compilatorul Svelte să-l elimine automat, deoarece componenta nu are niciun element cu acest atribut. Totuși, div nu poate fi inclus în wrapper-ul :global() deoarece acel stil ar afecta apoi fiecare div din aplicația ta.

###alte directive de bloc de stil

Utilizați theme() și este suportată, dar @screen nu este.

Plugin Vite

În aplicații Svelte sau SvelteKit, injectați stilurile generate direct în componentele Svelte, în timp ce plasați cel mai mic număr de stiluri necesare într-un fișier de stil global. Verificați exemplul SvelteKit în Stackblitz:

Open in StackBlitz

Instalare

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

Adăugați pluginul

Adăugați @unocss/svelte-scoped/vite la configurația Vite pentru a injecta stilurile generate direct în componentele Svelte:

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(),
  ],
})

Adăugați fișierul de configurare

Configurați fișierul uno.config.ts așa cum este descris de jos.

Stiluri globale

În general, toate stilurile sunt plasate într-o componentă individuală, dar există încă câteva stiluri care trebuie plasate într-un fișier de stil global: preflights, safelist și o opțională resetare (dacă utilizați opțiunea injectReset).

Adăugați placeholder-ul %unocss-svelte-scoped.global% într-un tag <head> în index.html. În Svelte, acest lucru este index.html. În SvelteKit, acest lucru va fi în app.html înainte de %sveltekit.head%:

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

Dacă utilizați SvelteKit, trebuie să adăugați și următorul în hook-ul transformPageChunk din fișierul src/hooks.server.js:

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
}

This transformation must be in a file whose path includes hooks and server (e.g. src/hooks.server.js, src/hooks.server.ts) as svelte-scoped will be looking in your server hooks file to replace unocss_svelte_scoped_global_styles with your global styles. Make sure to not import this transformation from another file, such as when using sequence from @sveltejs/kit/hooks.

In a regular Svelte project, Vite's transformIndexHtml hook will do this automatically.

Preprocesor Svelte

Utilizați stilurile utilitare pentru a crea o bibliotecă de componente care nu depinde de includerea unui fișier CSS companion utilizând un preprocesor pentru a plasa stilurile generate directly în componentele compilate. Verificați exemplul SvelteKit Library în Stackblitz:

Open in StackBlitz

Instalare

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

Adăugați preprocesor

Adăugați @unocss/svelte-scoped/preprocess la configurația Svelte:

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
}

Nu combinați numele de clase în timpul dezvoltării

Când folosești Svelte Scoped într-o aplicație normală, pluginul Vite detectează automat modul dev față de build. În timpul dezvoltării, clasele sunt păstrate distincte și hash-uite pe loc pentru a putea fi ușor activate/dezactivate în instrumentele de dezvoltare ale browser-ului. class="mb-1 mr-1" va deveni ceva de genul class="_mb-1_9hwi32 _mr-1_84jfy4". În producție, acestea vor fi compilate într-un singur nume de clasă folosind prefixul dorit (implicit uno-) și un hash bazat pe numele fișierului + numele claselor, de exemplu class="uno-84dke3".

If you want this same behavior when using the preprocessor, you must manually set the the combine option based on environemnt. One way to do this is to install cross-env and update your dev script to this:

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

Then adjust your svelte.config.js:

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

Adăugați fișier de configurare

Configurați fișierul uno.config.ts așa cum se descrie mai jos.

Preflights

Când folosești preprocesorul Svelte Scoped, ai opțiunea să includiți preflights în componenta specifică unde sunt necesare prin adăugarea uno-preflights ca atribut de stil.

html
<style uno-preflights></style>

Orice preflight-uri speciale care încep cu un punct, cum ar fi .prose :where(a):not(:where(.not-prose, .not-prose *)), vor fi încapsulate cu :global() pentru a evita eliminarea automată de către compilatorul Svelte.

Adăugați preflights într-o componentă specifică dacă clasele dvs. depind de preflights sau dacă componentele dvs. sunt consumate numai într-o aplicație care deja include preflights.

Safelist

Când folosești preprocesorul Svelte Scoped, ai opțiunea să includiți clasele de safelist într-o componentă specifică prin adăugarea uno-safelist ca atribut de stil.

html
<style uno-safelist></style>

Clasele de safelist vor fi încapsulate cu :global() pentru a evita eliminarea automată de către compilatorul Svelte.

Adăugați clasele de safelist într-o componentă specifică dacă clasele dvs. sunt utilizate într-o componentă care nu este consumată într-o aplicație care deja include preflights.

Configurare

Plasați setările UnoCSS într-un fișier uno.config.ts:

ts
import { defineConfig } from 'unocss'

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

Extractoarele nu sunt acceptate din cauza diferențelor dintre utilizarea globală normală UnoCSS și utilizarea Svelte Scoped. Preseturile și Transformatoarele sunt acceptate așa cum este descris în secțiunile următoare.

Presets support

În cauza naturii de a avea câteva stiluri necesare într-un fișier de stil global și tot ce altceva este conținut în fiecare componentă unde este necesar, preset-urile trebuie gestionate pe caz-caz:

PresetSupportedNotes
@unocss/preset-uno, @unocss/preset-mini, @unocss/preset-wind3, @unocss/preset-icons, @unocss/web-fontsThese and all community plugins, e.g. unocss-preset-forms, that only rely on rules/variants/preflights will work.
@unocss/preset-typographyDue to how this preset adds rulesets to your preflights you must add the prose class to your safelist when using this preset, otherwise the preflights will never be triggered. All other classes from this preset, e.g. prose-pink, can be component scoped.
@unocss/preset-rem-to-pxThis and all presets like it that only modify style output will work.
@unocss/preset-attributify-Preset won't work. Instead use unplugin-attributify-to-class Vite plugin (attributifyToClass({ include: [/\.svelte$/]})) before the Svelte Scoped Vite plugin
@unocss/preset-tagify-Presets that add custom extractors will not work. Create a preprocessor to convert <text-red>Hi</text-red> to <span class="text-red">Hi</span>, then create a PR to add the link here.

Pentru alte preseturi, dacă nu se bazează pe utilizarea tradițională class="...", va trebui mai întâi să preprocesați acele nume de clase în atributul class="...". Dacă adaugă preseturi precum clasa .prose din typography, va trebui să plasați clasele care declanșează adăugările presetului în safelist.

Transformers support

Transformatori sunt suportați pentru fișierele CSS (css|postcss|sass|scss|less|stylus|styl). Pentru a le utiliza, adăugați transformatorul în opțiunea cssFileTransformers din vite.config.ts:

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

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

INFO

Transformatori nu sunt suportați în componente Svelte deoarece Svelte Scoped funcționează într-un mod specific.

Scoped utility classes unleash creativity

Câteva sfaturi despre când ai putea dori să folosești stiluri scoped: Dacă ai ajuns în punctul vieții unui proiect mare în care, de fiecare dată când folosești o clasă precum .md:max-w-[50vw] pe care știi că este folosită doar o dată, te încrunți simțind cum dimensiunea fișierului tău CSS global devine din ce în ce mai mare, atunci încearcă acest pachet. Ezitarea de a folosi exact clasa de care ai nevoie inhibă creativitatea. Sigur, ai putea folosi --at-apply: md:max-w-[50vw] în blocul de stiluri, dar asta devine obositor, iar stilurile în context sunt utile. Mai mult, dacă dorești să incluzi o mare varietate de iconițe în proiectul tău, vei începe să simți greutatea adăugării lor în fișierul CSS global. Când fiecare componentă își poartă propria greutate a stilurilor și iconițelor, poți continua să îți extinți proiectul fără să fii nevoit să analizezi raportul cost-beneficiu al fiecărei noi adăugiri.

License

Released under the MIT License.