Custom Properties do CSS: Como Usar Variáveis Nativas e Aposentar o Pré-Processador
## O Sass resolveu um problema que já não existe
Em 2012, o CSS era primitivo. Não tinha variáveis, nesting, nem funções matemáticas. O Sass surgiu como salvação.
Hoje o cenário mudou radicalmente. Custom Properties são nativas, `calc()` faz contas, `@layer` organiza cascata e o nesting nativo já funciona em todos os browsers modernos. Mesmo assim, muitos projetos ainda carregam `node-sass` ou `dart-sass` como dependência obrigatória.
Vamos corrigir isso. Neste post, você vai dominar CSS Custom Properties do básico ao avançado — e entender exatamente quando o pré-processador se torna peso morto.
## O que são Custom Properties
Custom Properties são variáveis declaradas diretamente no CSS. Elas seguem a cascata, herdam valores do elemento pai e podem ser manipuladas em tempo real via JavaScript.
A sintaxe é simples. Declare com `--` e consuma com `var()`:
```css
:root {
--color-primary: #6366f1;
--spacing-md: 1rem;
--radius-lg: 12px;
}
.button {
background: var(--color-primary);
padding: var(--spacing-md);
border-radius: var(--radius-lg);
}
A diferença fundamental para variáveis do Sass? Elas existem em runtime. Variáveis Sass são resolvidas na compilação e viram valores estáticos. Custom Properties vivem no navegador e reagem a mudanças.
Essa diferença muda tudo.
Escopo e cascata: o superpoder ignorado
Variáveis Sass são globais ou locais ao arquivo. Custom Properties seguem a cascata do CSS. Isso significa que você pode redefinir valores por contexto sem criar classes extras.
:root {
--text-color: #1a1a2e;
--bg-color: #ffffff;
--surface-color: #f8f9fa;
}
.card {
color: var(--text-color);
background: var(--bg-color);
}
/* Redefinição por escopo */
.card--dark {
--text-color: #e2e8f0;
--bg-color: #1e293b;
--surface-color: #334155;
}
.card--brand {
--text-color: #ffffff;
--bg-color: #6366f1;
}
Perceba: o .card não mudou. Apenas redefinimos as variáveis no escopo do modificador. Todos os filhos de .card--dark herdam os novos valores automaticamente.
Tente fazer isso com Sass. Você vai precisar de mixins, maps e uma quantidade absurda de boilerplate.
Escopo em componentes reais
Veja um exemplo prático com um sistema de alertas:
.alert {
--alert-bg: #f0f9ff;
--alert-border: #3b82f6;
--alert-text: #1e40af;
background: var(--alert-bg);
border-left: 4px solid var(--alert-border);
color: var(--alert-text);
padding: 1rem 1.25rem;
border-radius: 6px;
}
.alert--success {
--alert-bg: #f0fdf4;
--alert-border: #22c55e;
--alert-text: #166534;
}
.alert--danger {
--alert-bg: #fef2f2;
--alert-border: #ef4444;
--alert-text: #991b1b;
}
.alert--warning {
--alert-bg: #fffbeb;
--alert-border: #f59e0b;
--alert-text: #92400e;
}
Uma única regra base. Variantes alteram apenas as variáveis. Zero duplicação.
Fallbacks inteligentes
A função var() aceita um segundo argumento: o valor de fallback. Essa mecânica é mais poderosa do que parece.
.component {
/* Fallback simples */
color: var(--custom-color, #333333);
/* Fallback encadeado */
background: var(--theme-bg, var(--default-bg, #ffffff));
/* Fallback com calc */
padding: var(--spacing, calc(1rem + 4px));
}
Isso permite criar componentes que funcionam com ou sem um sistema de design tokens definido. O componente tenta usar o token. Se não existir, usa o fallback.
Padrão de API pública para componentes
Essa técnica cria uma "API" de customização para seus componentes CSS:
/* O componente define defaults internos */
.modal {
--_modal-width: var(--modal-width, 480px);
--_modal-padding: var(--modal-padding, 2rem);
--_modal-radius: var(--modal-radius, 16px);
--_modal-bg: var(--modal-bg, #ffffff);
width: var(--_modal-width);
padding: var(--_modal-padding);
border-radius: var(--_modal-radius);
background: var(--_modal-bg);
}
O prefixo --_ indica variável privada. As variáveis sem prefixo são a API públi
Leia o artigo completo em https://vivodecodigo.com.br/react/css-custom-properties-variaveis-nativas-aposentar-pre-processador