Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoAvançadocódigo testado

Maps e loops no Sass: @each, @for e utilitários gerados

Como guardar a paleta num map, gerar dezenas de classes com @each e @for, e o que acontece quando a chave pedida não existe.

Rodolfo Mori5 min de leitura

Map guarda pares de chave e valor; @each percorre coleções; @for percorre uma faixa numérica. Juntos, eles transformam tokens em CSS. O benefício é uma fonte de dados única. O risco é gerar centenas de regras que ninguém inspeciona.

Cada exemplo foi enviado ao Dart Sass 1.103.1 pela entrada padrão, sem sourcemap e com estilo expandido. Os casos válidos terminaram com status 0, e as saídas relevantes estão registradas ao lado de cada trecho.

O primeiro map e map.get

Carregue sass:map, declare pares entre parênteses e leia uma chave:

css
@use "sass:map";
$colors: (
  primary: #6d28d9,
  success: #16a34a
);

.button { color: map.get($colors, primary); }
.button { color: #6d28d9; }

O map não aparece na saída. Ele é adequado quando a coleção alimenta várias operações ou precisa ser configurada como unidade. Para duas constantes sem relação, variáveis individuais podem ser mais legíveis.

Gerar classes com @each

@each $name, $value in $colors desempacota cada par. Interpolação coloca a chave no seletor:

css
$colors: (
  primary: #6d28d9,
  success: #16a34a,
  danger: #dc2626
);

@each $name, $value in $colors {
  .text-#{$name} { color: $value; }
}
.text-primary { color: #6d28d9; }

.text-success { color: #16a34a; }

.text-danger { color: #dc2626; }

Três entradas geraram três regras. Antes de ampliar para dez propriedades e vinte cores, defina quais combinações o produto usa. Gerar o produto cartesiano por conveniência aumenta a folha mesmo quando quase todas as classes ficam ociosas.

Maps aninhados para temas

Um valor de map pode ser outro map. Dart Sass atual aceita várias chaves em map.get, atravessando níveis:

css
@use "sass:map";
$theme: (
  light: (surface: white, text: #111827),
  dark: (surface: #111827, text: white)
);

.dark {
  background: map.get($theme, dark, surface);
  color: map.get($theme, dark, text);
}
.dark { background: #111827; color: white; }

Para tema que muda no navegador, emita esses valores como custom properties em vez de duplicar cada componente. O map pode ser a fonte do build; a cascata deve continuar responsável pela troca em runtime.

Chave ausente vira null e pode sumir

map.get não lança erro para chave desconhecida. Ele devolve null, e uma declaração cujo valor é null não é emitida. Como a regra fica vazia, ela também some:

css
@use "sass:map";
$colors: (primary: #6d28d9);
.missing { color: map.get($colors, warning); }

O compilador terminou com status 0 e não imprimiu CSS. Esse silêncio é conveniente para configuração opcional e perigoso para token obrigatório. Uma classe sem cor pode chegar ao deploy sem warning.

Validar token obrigatório com map.has-key

Envolva o acesso numa função quando ausência for defeito de contrato:

css
@use "sass:map";
$colors: (primary: #6d28d9);

@function token($name) {
  @if not map.has-key($colors, $name) {
    @error "Token #{$name} não existe";
  }
  @return map.get($colors, $name);
}

.alert { color: token(warning); }
Error: "Token warning não existe" ╷ 11 │ .alert { color: token(warning); } │ ^^^^^^^^^^^^^^ ╵ map-missing.scss 11:17 root stylesheet

Agora o build falha perto do consumo e diz qual chave faltou. Teste também a configuração padrão do módulo para não descobrir um token obrigatório apenas em uma aplicação consumidora.

@for through: incluir o último número

Use faixa quando os itens são numéricos e contíguos. through inclui três:

css
@for $i from 1 through 3 {
  .span-#{$i} { grid-column: span $i; }
}
.span-1 { grid-column: span 1; }

.span-2 { grid-column: span 2; }

.span-3 { grid-column: span 3; }

O seletor usa interpolação; o valor mantém o número. Defina um limite ligado ao sistema real de grid, não um valor alto “para garantir”. Cada iteração publica uma classe.

@for to: parar antes do limite

Trocar uma palavra muda a quantidade. to 3 gera um e dois:

css
@for $i from 1 to 3 {
  .step-#{$i} { z-index: $i; }
}
.step-1 { z-index: 1; }

.step-2 { z-index: 2; }

Esse detalhe causa lacunas silenciosas. Se o domínio diz “de 1 até 3 inclusive”, through expressa melhor. Para uma lista de nomes ou valores irregulares, prefira @each.

Quanto CSS o loop realmente gerou

Para medir em vez de estimar, montei cinco famílias com nove tons cada. As chaves de família estão entre aspas porque nomes como blue e red também são cores reconhecidas pelo Sass; assim a interpolação compilou sem warnings.

css
$palette: (
  "violet": (
    50: #f5f3ff, 100: #ede9fe, 200: #ddd6fe,
    300: #c4b5fd, 400: #a78bfa, 500: #8b5cf6,
    600: #7c3aed, 700: #6d28d9, 900: #4c1d95
  ),
  "blue": (
    50: #eff6ff, 100: #dbeafe, 200: #bfdbfe,
    300: #93c5fd, 400: #60a5fa, 500: #3b82f6,
    600: #2563eb, 700: #1d4ed8, 900: #1e3a8a
  ),
  "green": (
    50: #f0fdf4, 100: #dcfce7, 200: #bbf7d0,
    300: #86efac, 400: #4ade80, 500: #22c55e,
    600: #16a34a, 700: #15803d, 900: #14532d
  ),
  "amber": (
    50: #fffbeb, 100: #fef3c7, 200: #fde68a,
    300: #fcd34d, 400: #fbbf24, 500: #f59e0b,
    600: #d97706, 700: #b45309, 900: #78350f
  ),
  "red": (
    50: #fef2f2, 100: #fee2e2, 200: #fecaca,
    300: #fca5a5, 400: #f87171, 500: #ef4444,
    600: #dc2626, 700: #b91c1c, 900: #7f1d1d
  )
);

@each $family, $tones in $palette {
  @each $tone, $value in $tones {
    .bg-#{$family}-#{$tone} {
      background-color: $value;
    }
  }
}

Compilei o arquivo em estilo expandido, contei seletores, linhas e bytes, e comprimi pela entrada padrão para o cabeçalho do gzip não carregar nome de arquivo:

bash
npx --no-install sass matrix-5x9.scss matrix-5x9.css --no-source-map --style=expanded
rg -c '^\.bg-' matrix-5x9.css
wc -l -c matrix-5x9.css
gzip -9 -c < matrix-5x9.css | wc -c
45 179 2136 matrix-5x9.css 415

O Sass 1.103.1 terminou com status 0 e sem warnings. A matriz 5 × 9 publicou 45 seletores em 179 linhas: 2.136 bytes, aproximadamente 2,09 KiB, e 415 bytes com gzip -9. A primeira regra foi .bg-violet-50; a última, .bg-red-900. Compressão reduziu a transferência, mas as 45 classes continuam na cascata mesmo que a página use somente duas.

Use allowlists por propriedade, gere somente a API documentada e meça tamanho bruto e gzip. Se o projeto quer utilitários sob demanda, uma ferramenta que analisa conteúdo pode ser mais adequada que gerar todas as combinações no Sass.

Organizar tokens como API de módulo

Mantenha map privado e exponha funções como token() ou variáveis públicas selecionadas. Assim, o formato interno pode mudar sem obrigar consumidores a conhecer níveis e chaves. Combine com @use e @forward para uma fachada estável.

Defina um schema humano mesmo que Sass não tenha tipos de objeto formais. Documente chaves obrigatórias, unidades aceitas e se mapas do consumidor são substituídos ou mesclados. Uma configuração que aceita qualquer estrutura só transfere o erro para uma chamada distante. Funções de acesso podem validar e emitir mensagem com o caminho procurado.

Ao mesclar temas, escolha precedência explicitamente. Padrão primeiro e sobrescrita depois costuma ser previsível, mas um map aninhado pode exigir merge profundo. Teste uma chave substituída, uma chave nova e uma seção ausente. O CSS final deve mostrar que somente as decisões esperadas mudaram.

Versione a API pelos nomes semânticos, não pela paleta visual. danger pode mudar de tom sem obrigar componentes a conhecer red-600; já remover danger quebra o contrato. Se a camada precisa expor escala primitiva e tokens semânticos, mantenha maps separados e faça componentes consumir o segundo.

Loops merecem testes de contagem. Registre quantas regras uma configuração padrão produz e coloque um limite no CI para detectar expansão acidental. Um novo estado multiplicado por cores, tamanhos e breakpoints pode aumentar a folha em milhares de seletores sem alterar muito o fonte. Métrica torna esse custo visível durante a revisão.

Para depurar, imprima temporariamente valores com @debug e remova a chamada antes de publicar. Confira chave e tipo no ponto em que entram no loop. Quando o seletor gerado está errado, investigue interpolação; quando a propriedade some, investigue null; quando o build explode, leia a função de validação e a pilha.

Revise funções e operações para validar entradas. O guia de Sass ajuda a decidir se a geração traz valor ou apenas recria uma biblioteca de utilitários dentro do projeto.

  • sass
  • map
  • each
  • for
  • utilitários
  • design tokens

Perguntas frequentes

Map Sass chega ao navegador?
Não. Ele existe no build. Loops e funções leem seus dados e emitem valores ou regras CSS concretas.
Qual a diferença entre through e to no @for?
through inclui o limite final; to para antes dele. De 1 through 3 gera 1, 2 e 3, enquanto de 1 to 3 gera somente 1 e 2.
O que map.get devolve para chave ausente?
Devolve null. Como propriedades com null não são emitidas, uma regra pode desaparecer silenciosamente; valide chaves quando ausência for erro.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Dart Sass 1.103.1 (dart2js 3.13.1), Node 26.3.0, macOS, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. Sass — sass:map — sass-lang.com
  2. Sass — @each — sass-lang.com
  3. Sass — @for — sass-lang.com

Continue por aqui