Sobrescritas com escopo
Mude uma área, um estilo ou uma parte sem mexer no resto. Tokens num elemento, regras @scope e providers aninhados, e como as camadas cml.* decidem quem vence.
// você vai aprender
- Três jeitos de limitar uma sobrescrita: um token num elemento, uma regra
@scope, um provider aninhado - A ordem das camadas
cml.*, e por que o seu CSS vence sem!important - As armadilhas: ilhas, estados que você sobrescreve sem querer,
!important, movimento reduzido
Experimente
O card tem uma "zona de perigo" (<div className="danger-zone">). Cada opção muda a aparência só dessa área; o código que aparece com ela é o que roda.
Espaço de trabalho
Zona de perigo
Excluir o espaço apaga 14 projetos para todo mundo.
<div className="danger-zone">
<Text>Zona de perigo</Text>
<Button variant="outline">Transferir</Button>
<Button variant="danger">Excluir espaço</Button>
</div>
Sem sobrescrita — o estilo como vem.
Escolha a ferramenta mais estreita
| Ferramenta | Use para | Alcança |
|---|---|---|
| Um token num elemento | Valores: cor, raio, tamanho, espaçamento | Esse elemento e tudo dentro dele |
@scope (…) to (…) | Tudo o que um token não faz | Da raiz do escopo até o limite que você definir |
Um StyleProvider aninhado | Outro estilo, outro modo ou outra marca | A subárvore dele, popups incluídos |
Comece pelos tokens. Um token mantém os estados do estilo funcionando (hover, foco, desabilitado), porque o estilo continua escrevendo as regras; você só muda os valores que elas leem.
/* Controles mais altos só no checkout */
.checkout {
--cml-control-height: 2.75rem;
--cml-field-height: 2.75rem;
}O elemento precisa estar dentro do provider. Todo elemento [data-style] declara todos os tokens de novo, então uma classe num wrapper em volta do StyleProvider é sobrescrita antes de chegar aos componentes.
Quando a mudança não é um valor (uma borda que não existe, outro layout), escreva uma regra dentro de @scope. Acrescente to ([data-style]) para ela parar nos estilos aninhados, como fazem os arquivos de estilo:
@scope (.pricing) to ([data-style]) {
[data-slot="card"] {
border-style: dashed;
}
}Para uma aparência totalmente diferente numa área, aninhe um provider. Ele é uma ilha: parte de tokens limpos, e os popups dele mantêm o estilo dele.
<StyleProvider styleName="minimal">
<Article />
<StyleProvider styleName="retro" mode="dark">
<Terminal />
</StyleProvider>
</StyleProvider>
A ordem das camadas
O base.css declara quatro camadas antes de qualquer outra coisa. As camadas posteriores vencem as anteriores, e o CSS que não está em nenhuma camada vence todas elas:
@layer cml.tokens, cml.components, cml.style, cml.preferences;| Camada | Guarda |
|---|---|
cml.tokens | O padrão de cada token (os valores do minimal) no :root e em [data-style] |
cml.components | As regras dos componentes, quase todas dentro de :where(), para não somarem especificidade |
cml.style | Os arquivos de estilo: valores de token em [data-style="name"] e as regras @scope do estilo |
cml.preferences | Movimento reduzido e cores forçadas |
| o seu CSS sem camada | Vence tudo acima, seja qual for a especificidade |
Se o seu CSS fica numa camada (um design system, um framework de CSS), ordene as camadas uma vez, no topo da folha de estilo principal, antes de qualquer import. Uma camada listada depois de cml vence todas as subcamadas dela:
@layer cml, app;
@import "@camaleo/styles/base.css";
@import "@camaleo/styles/glass.css";
@layer app {
[data-style] { --cml-radius-surface: 20px; }
}Usa Tailwind? Os utilitários dele também ficam em camadas, e qual lado vence depende da mesma ordem. O guia Tailwind CSS tem a linha que você precisa acrescentar.
Armadilhas de especificidade
- Regras sem camada vencem os estados do estilo.
[data-slot="button"] { background: navy }fora de qualquer camada também vence as regras:hover,[data-disabled]e:focus-visiblede todos os estilos, e o botão para de reagir. Mude--cml-accente--cml-accent-hover, ou escreva os estados você mesmo. !importantvira as camadas de cabeça para baixo. Uma declaração importante numa camada anterior vence uma numa camada posterior, e qualquer importante em camada vence um sem camada. Você nunca precisa dele para vencer a biblioteca; deixe-o de fora.- O seu CSS também vence
cml.preferences. Se você acrescentar uma transição ou uma animação, coloque-a dentro de@media (prefers-reduced-motion: no-preference)você mesmo. - Um escopo sem limite vaza para as ilhas.
@scope (.pricing)também estiliza um provider aninhado dentro de.pricing; acrescenteto ([data-style]). - Um token definido alto demais se perde. No
:rootou fora do provider, ele é sobrescrito pelas declarações do próprio provider. Use[data-style]ou um elemento dentro dele.
Antes de publicar
- Tokens primeiro; uma regra só quando nenhum token resolve
- Sobrescritas de token num elemento dentro do provider
- Regras
@scopeterminam comto ([data-style]) - Nada de
!important; CSS em camada listado depois decmlnuma única declaração@layer - Hover, foco e desabilitado continuam visíveis depois da mudança, no modo claro e no escuro