Svelte Scoped
Coloque o CSS gerado para os estilos de utilitários de cada componente Svelte diretamente no bloco <style>
do componente Svelte, em vez de em um arquivo CSS global.
Este componente:
<div class="mb-1" />
é transformado em:
<div class="uno-ei382o" />
<style>
:global(.uno-ei382o) {
margin-bottom: 0.25rem;
}
</style>
Quando usar
Caso de Uso | Descrição | Pacote a Usar | |
---|---|---|---|
Aplicativos menores | ❌ | Ter 1 arquivo CSS global é mais conveniente. Use o plugin Vite regular para Svelte/SvelteKit. | unocss/vite |
Aplicativos maiores | ✅ | Svelte Scoped pode ajudar você a evitar um arquivo CSS global cada vez maior. | @unocss/svelte-scoped/vite |
Biblioteca de componentes | ✅ | Os estilos gerados são colocados diretamente nos componentes construídos sem a necessidade de usar o UnoCSS no pipeline de compilação de um aplicativo consumidor. | @unocss/svelte-scoped/preprocess |
Como funciona
Uma configuração regular do UnoCSS/Tailwind CSS coloca os estilos de utilitários em um arquivo CSS global com a ordenação adequada. Em contraste, o Svelte Scoped distribui seus estilos em vários arquivos de componentes Svelte com ordem arbitrária. No entanto, deve manter os estilos de utilitários globais para permitir que eles sejam sensíveis ao contexto, conforme necessário para coisas como direita para esquerda e outros casos de uso listados abaixo. Isso apresenta um desafio que é resolvido usando o wrapper :global()
do Svelte para optar por não usar o método de hash de CSS padrão do Svelte e, em vez disso, usar um hash baseado no nome do arquivo + nome(s) da(s) classe(s) para compilar nomes de classes exclusivos que podem ser globais sem conflitos de estilo.
Uso
Como o Svelte Scoped reescreve seus nomes de classes de utilitários, você está limitado a onde pode escrevê-los:
Sintaxe Suportada | Exemplo |
---|---|
Atributo de classe | <div class="mb-1" /> |
Diretiva de classe | <div class:mb-1={condition} /> |
Atalho de diretiva de classe | <div class:logo /> |
Prop de classe | <Button class="mb-1" /> |
O Svelte Scoped é projetado para ser um substituto direto para um projeto que usa estilos de utilitários. Como tal, expressões encontradas dentro de atributos de classe também são suportadas (por exemplo, <div class="mb-1 {foo ? 'mr-1' : 'mr-2'}" />
) mas recomendamos que você use a sintaxe de diretiva de classe daqui para frente. Observe também que se você usou nomes de classes de outras maneiras, como colocá-los em um bloco <script>
ou usar o modo de atributos, precisará tomar medidas adicionais antes de usar o Svelte Scoped. Você pode utilizar a opção safelist
e também verificar a seção presets abaixo para mais dicas.
Sensível ao contexto
Mesmo que os estilos sejam distribuídos pelos componentes Svelte do seu aplicativo, eles ainda são classes globais e funcionarão em relação aos elementos encontrados fora de seus componentes específicos. Aqui estão alguns exemplos:
Dependente do pai
Classes que dependem de atributos encontrados em um componente pai:
<div class="dark:mb-2 rtl:right-0"></div>
se transformam em:
<div class="uno-3hashz"></div>
<style>
:global(.dark .uno-3hashz) {
margin-bottom: 0.5rem;
}
:global([dir="rtl"] .uno-3hashz) {
right: 0rem;
}
</style>
Influência dos filhos
Você pode adicionar espaço entre 3 elementos filhos, alguns dos quais estão em componentes separados:
<div class="space-x-1">
<div>Status: online</div>
<Button>FAQ</Button>
<Button>Login</Button>
</div>
se transforma em:
<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>
Passando classes para componentes filhos
Você pode adicionar uma prop class
a um componente para permitir passar classes personalizadas sempre que esse componente for consumido.
<Button class="px-2 py-1">Login</Button>
se transforma em:
<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>
Uma maneira fácil de implementar a classe em um componente receptor seria colocá-las em um elemento usando {$$props.class}
como em div class="{$$props.class} foo bar" />
.
Diretivas de aplicação
Você pode usar diretivas de aplicação dentro de seus blocos <style>
com --at-apply
ou @apply
ou um valor personalizado definido usando a opção applyVariables
.
O Svelte Scoped até lida corretamente com classes dependentes de contexto como dark:text-white
que o pacote regular @unocss/transformer-directives
não pode lidar adequadamente porque não foi construído especificamente para blocos de estilo Svelte. Por exemplo, com o Svelte Scoped, este componente:
<div />
<style>
div {
--at-apply: rtl:ml-2;
}
</style>
será transformado em:
<div />
<style>
:global([dir=\\"rtl\\"]) div {
margin-right: 0.5rem;
}
</style>
Para que rtl:ml-2
funcione corretamente, o seletor [dir="rtl"]
é envolvido com :global()
para impedir que o compilador Svelte o remova automaticamente, pois o componente não tem nenhum elemento com esse atributo. No entanto, div
não pode ser incluído no wrapper :global()
porque esse estilo afetaria então todos os div
em seu aplicativo.
Outras diretivas de bloco de estilo
Usar theme() também é suportado, mas @screen não é.
Plugin Vite
Em aplicativos Svelte ou SvelteKit, injete estilos gerados diretamente em seus componentes Svelte, colocando o mínimo de estilos necessários em uma folha de estilo global. Confira o exemplo SvelteKit no Stackblitz:
Instalar
pnpm add -D unocss @unocss/svelte-scoped
yarn add -D unocss @unocss/svelte-scoped
npm install -D unocss @unocss/svelte-scoped
bun add -D unocss @unocss/svelte-scoped
Adicionar plugin
Adicione @unocss/svelte-scoped/vite
à sua configuração do Vite:
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', // consulte a definição de tipo para todas as opções de redefinição incluídas ou como passar as suas próprias
// ...outras opções do Svelte Scoped
}),
sveltekit(),
],
})
Adicionar arquivo de configuração
Configure seu arquivo uno.config.ts
conforme descrito abaixo.
Estilos globais
Embora quase todos os estilos sejam colocados em componentes individuais, ainda há alguns que devem ser colocados em uma folha de estilo global: preflights, safelist e uma redefinição opcional (se você usar a opção injectReset
).
Adicione o espaço reservado %unocss-svelte-scoped.global%
à sua tag <head>
. No Svelte, isso é index.html
. No SvelteKit, isso estará em app.html
antes de %sveltekit.head%
:
<head>
<!-- ... -->
<title>SvelteKit usando UnoCSS Svelte Scoped</title>
%unocss-svelte-scoped.global%
%sveltekit.head%
</head>
Se estiver usando SvelteKit, você também deve adicionar o seguinte ao hook transformPageChunk
em seu arquivo src/hooks.server.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
}
Esta transformação deve estar em um arquivo cujo caminho inclua hooks
e server
(por exemplo, src/hooks.server.js
, src/hooks.server.ts
), pois o svelte-scoped
procurará em seu arquivo de hooks do servidor para substituir unocss_svelte_scoped_global_styles
por seus estilos globais. Certifique-se de não importar esta transformação de outro arquivo, como ao usar sequence de @sveltejs/kit/hooks
.
Em um projeto Svelte regular, o hook transformIndexHtml
do Vite fará isso automaticamente.
Svelte Preprocessor
Use estilos utilitários para construir uma biblioteca de componentes que não dependa da inclusão de um arquivo CSS complementar, usando um pré-processador para colocar estilos gerados diretamente nos componentes construídos. Confira o exemplo de biblioteca SvelteKit no Stackblitz:
Instalar
pnpm add -D unocss @unocss/svelte-scoped
yarn add -D unocss @unocss/svelte-scoped
npm install -D unocss @unocss/svelte-scoped
bun add -D unocss @unocss/svelte-scoped
Adicionar pré-processador
Adicione @unocss/svelte-scoped/preprocess
à sua configuração do Svelte:
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({
// ... opções do pré-processador
}),
],
// outras configurações do Svelte
}
Não combine nomes de classes no desenvolvimento
Ao usar o Svelte Scoped em um aplicativo normal, o plugin Vite detectará automaticamente dev
vs build
. No desenvolvimento, as classes serão mantidas distintas e com hash no local para facilitar a ativação/desativação nas ferramentas de desenvolvedor do seu navegador. class="mb-1 mr-1"
se transformará em algo como class="_mb-1_9hwi32 _mr-1_84jfy4
. Na produção, estes serão compilados em um único nome de classe usando seu prefixo desejado, uno-
por padrão, e um hash baseado no nome do arquivo + nomes das classes, por exemplo, class="uno-84dke3
.
Se você quiser esse mesmo comportamento ao usar o pré-processador, você deve definir manualmente a opção combine
com base no ambiente. Uma maneira de fazer isso é instalar o cross-env e atualizar seu script de desenvolvimento para:
"dev": "cross-env NODE_ENV=development vite dev"
Então ajuste seu svelte.config.js:
+const prod = process.env.NODE_ENV !== 'development'
const config = {
preprocess: [
vitePreprocess(),
UnoCSS({
+ combine: prod,
}),
],
}
Adicionar arquivo de configuração
Configure seu arquivo uno.config.ts
conforme descrito abaixo.
Preflights
Ao usar o pré-processador, você tem a opção de incluir preflights nos componentes específicos onde eles são necessários adicionando uno-preflights
como um atributo de estilo.
<style uno-preflights></style>
Quaisquer preflights especiais que começam com um ponto, como .prose :where(a):not(:where(.not-prose, .not-prose *))
, serão envolvidos com :global()
para evitar serem automaticamente removidos pelo compilador Svelte.
Adicionar preflights em componentes individuais é desnecessário se suas classes não dependem de preflights ou se seus componentes construídos estão sendo consumidos apenas em aplicativos que já incluem preflights.
Lista de segurança
Ao usar o pré-processador, você tem a opção de incluir classes da lista de segurança em um componente adicionando uno-safelist
como um atributo de estilo.
<style uno-safelist></style>
Seus estilos da lista de segurança serão envolvidos com :global()
para evitar serem automaticamente removidos pelo compilador Svelte.
Configuração
Coloque suas configurações do UnoCSS em um arquivo uno.config.ts
:
import { defineConfig } from 'unocss'
export default defineConfig({
// ...opções do UnoCSS
})
Extratores não são suportados devido às diferenças no uso global normal do UnoCSS e no uso do Svelte Scoped. Presets e Transformadores são suportados conforme descrito nas seções seguintes. Veja Arquivo de Configuração e Referência de Configuração para todos os outros detalhes.
Suporte a presets
Devido à natureza de ter alguns estilos necessários em uma folha de estilo global e todo o resto contido em cada componente onde necessário, os presets precisam ser tratados caso a caso:
Preset | Suportado | Notas |
---|---|---|
✅ | Estes e todos os plugins da comunidade, por exemplo, unocss-preset-forms, que dependem apenas de regras/variantes/preflights funcionarão. | |
@unocss/preset-typography | ✅ | Devido à forma como este preset adiciona conjuntos de regras aos seus preflights, você deve adicionar a classe prose à sua lista de segurança ao usar este preset, caso contrário, os preflights nunca serão acionados. Todas as outras classes deste preset, por exemplo, prose-pink , podem ter escopo de componente. |
@unocss/preset-rem-to-px | ✅ | Este e todos os presets como ele que apenas modificam a saída de estilo funcionarão. |
@unocss/preset-attributify | - | O preset não funcionará. Em vez disso, use o plugin Vite unplugin-attributify-to-class (attributifyToClass({ include: [/\.svelte$/]}) ) antes do plugin Vite Svelte Scoped |
@unocss/preset-tagify | - | Presets que adicionam extratores personalizados não funcionarão. Crie um pré-processador para converter <text-red>Hi</text-red> em <span class="text-red">Hi</span> , então crie um PR para adicionar o link aqui. |
Para outros presets, se eles não dependem do uso tradicional de class="..."
, você precisará primeiro pré-processar esses nomes de classe no atributo class="..."
. Se eles adicionarem presets como a classe .prose
da tipografia, você precisará colocar as classes que acionam as adições do preset em sua lista de segurança.
Suporte a transformadores
Os transformadores são suportados para seus arquivos CSS (css|postcss|sass|scss|less|stylus|styl). Para usá-los, adicione o transformador na opção cssFileTransformers
em seu vite.config.ts
:
import transformerDirectives from '@unocss/transformer-directives'
export default defineConfig({
plugins: [
UnoCSS({
cssFileTransformers: [transformerDirectives()],
}),
sveltekit(),
],
})
INFO
Transformadores não são suportados em componentes Svelte devido à forma como o Svelte Scoped funciona.
Classes utilitárias com escopo liberam a criatividade
Alguns conselhos sobre quando você pode querer usar estilos com escopo: Se você chegou ao ponto em um projeto grande em que toda vez que usa uma classe como .md:max-w-[50vw]
que você sabe que só é usada uma vez, você se arrepia ao sentir o tamanho de sua folha de estilo global aumentando cada vez mais, então experimente este pacote. Hesitação em usar exatamente a classe que você precisa inibe a criatividade. Claro, você poderia usar --at-apply: md:max-w-[50vw]
no bloco de estilo, mas isso se torna tedioso e estilos em contexto são úteis. Além disso, se você gostaria de incluir uma grande variedade de ícones em seu projeto, você começará a sentir o peso de adicioná-los à folha de estilo global. Quando cada componente carrega o peso de seus próprios estilos e ícones, você pode continuar expandindo seu projeto sem ter que analisar o custo-benefício de cada nova adição.
Licença
- Licença MIT © 2022-PRESENTE Jacob Bowdoin