Mixin no Sass: @mixin, @include, argumentos e @content
Como escrever mixins com valores padrão, blocos com @content e breakpoints nomeados — e quanto CSS duplicado cada @include gera.
Mixin é uma receita que emite CSS onde for incluída. Ele aceita argumentos,
valores padrão e até um bloco de conteúdo. Isso resolve repetição estrutural,
mas não cria compartilhamento no navegador: cada @include copia resultado
para a folha final.
Cada exemplo foi enviado ao Dart Sass 1.103.1 pela entrada padrão, sem sourcemap e com estilo expandido. Os casos válidos encerraram com status 0; abaixo, cada saída aparece junto do trecho que a produziu.
Se o seletor externo ainda parece misterioso, revise aninhamento no Sass. Argumentos também seguem as regras apresentadas em variáveis no Sass.
O primeiro @mixin e o primeiro @include
Declare a receita uma vez e inclua onde as declarações precisam aparecer:
@mixin focus-ring {
outline: 3px solid #a78bfa;
outline-offset: 2px;
}
.button:focus-visible { @include focus-ring; }O nome do mixin sumiu. Use esse formato para um contrato pequeno e estável, como o tratamento acessível de foco. Para uma única declaração repetida duas vezes, uma custom property costuma ser mais direta.
Argumentos obrigatórios, padrão e nomeados
Parâmetros transformam uma receita fixa numa família controlada. $bg é
obrigatório; os demais têm padrão:
@mixin button($bg, $color: white, $radius: .5rem) {
background: $bg;
color: $color;
border-radius: $radius;
}
.save { @include button(#6d28d9); }
.cancel { @include button($bg: #e5e7eb, $color: #111827); }Argumentos nomeados documentam a chamada e permitem pular opcionais. Porém, o
nome vira parte da API: renomear $color quebra consumidores que o citam.
O erro de argumento ausente
Se não há padrão, a chamada precisa fornecer o valor. O compilador mostra tanto a invocação quanto a declaração do contrato:
@mixin badge($bg, $color) {
background: $bg;
color: $color;
}
.badge { @include badge(#dc2626); }Não resolva com um padrão arbitrário. Se não existe valor seguro, mantenha o argumento obrigatório para o erro acontecer no build, antes de um botão ficar ilegível em produção.
Undefined mixin: duas causas para a mesma mensagem
Um nome que não foi declarado nem carregado falha antes de emitir CSS. Este arquivo foi executado sozinho, e o processo encerrou com status 65:
.card {
@include flex-centro;
}Há duas verificações objetivas: confirme se o nome foi declarado sem erro de
digitação e, quando ele vem de outro módulo, carregue esse módulo com @use e
chame o mixin pelo namespace. Criar outro mixin com o mesmo nome apenas para o
build passar esconderia a dependência ausente.
@content: o chamador entrega o miolo
Um mixin de contexto abre uma media query e posiciona dentro dela o bloco
recebido por @content:
@mixin respond($width) {
@media (min-width: $width) { @content; }
}
.grid {
display: grid;
@include respond(48rem) {
grid-template-columns: 1fr 1fr;
}
}O mixin padroniza a condição, enquanto o componente decide a mudança. Dê nomes
semânticos aos breakpoints apenas quando a equipe tem um contrato real; esconder
48rem atrás de “tablet” não torna a decisão automaticamente melhor.
Contexto de tema com & e @content
Também é possível colocar o seletor atual dentro de um contexto. A interpolação
monta o valor do atributo, e & representa .card:
@mixin theme($name) {
[data-theme="#{$name}"] & { @content; }
}
.card {
@include theme(dark) {
background: #111827;
color: white;
}
}Para muitas cores, prefira custom properties e troque somente os tokens. O mixin faz sentido quando o contexto muda estrutura, não para duplicar um tema inteiro.
Condição dentro do mixin
Um argumento pode escolher uma variação limitada. Este triângulo aceita direção
e mantém up como padrão:
@mixin triangle($size, $color, $direction: up) {
width: 0;
height: 0;
border: $size solid transparent;
@if $direction == up { border-bottom-color: $color; }
}
.arrow { @include triangle(8px, #6d28d9); }Se o número de ramos cresce sem parar, o mixin está virando componente. Prefira classes e propriedades explícitas a uma linguagem paralela difícil de testar.
Quanto CSS cada @include copia
Para medir a duplicação, compilei quatro declarações em quarenta componentes. O
laço serve apenas para manter o arquivo de entrada curto; cada volta faz um
@include real:
@mixin component-base {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem;
}
@for $i from 1 through 40 {
.component-#{$i} {
@include component-base;
}
}Compilei em estilo expandido, contei seletores, linhas e bytes, e passei o CSS
pela entrada padrão do gzip -9 para não incluir nome de arquivo no cabeçalho:
npx --no-install sass mixin-40.scss mixin-40.css --no-source-map --style=expanded
rg -c '^\.component-' mixin-40.css
wc -l -c mixin-40.css
gzip -9 -c < mixin-40.css | wc -cO Sass 1.103.1 gerou quarenta seletores e 160 declarações: 3.670 bytes, ou aproximadamente 3,58 KiB, antes da compressão. O gzip reduziu essa folha repetitiva a 216 bytes, mas não transformou as quarenta regras numa referência compartilhada dentro do CSS.
Gzip reconhece repetição na transferência, mas o navegador ainda recebe regras
e a cascata ainda precisa processá-las. Antes de extrair, conte chamadas e leia
a saída. Às vezes uma classe .button compartilhada e uma custom property por
variante são menores e mais fáceis de inspecionar.
Checklist para um mixin saudável
Um bom mixin tem nome que explica o contrato, poucos argumentos, padrões seguros, saída previsível e mais de um consumidor real. Ele não lê dez globais nem emite um componente inteiro escondido. A assinatura deve caber numa linha de chamada:
Também observe a direção da dependência. Um componente pode depender de um
mixin de infraestrutura, como foco ou breakpoint; um mixin global não deve
conhecer .checkout-card ou outra classe de produto. Quando a receita começa a
receber parâmetros como $show-icon, $compact, $ecommerce e $legacy, ela
está acumulando decisões que pertencem a componentes separados.
Teste mixins pelo CSS, não pela existência da declaração. Monte chamadas com valor padrão, valor nomeado e limite inválido; salve as saídas importantes ou use testes de snapshot na biblioteca. Uma mudança de uma linha no mixin pode alterar dezenas de seletores. A revisão precisa enxergar esse alcance antes de publicar uma nova versão.
Versão também importa para consumidores. Renomear argumento nomeado é quebra de API; remover padrão torna chamada antes válida um erro; trocar ordem de emissão pode alterar a cascata. Trate um mixin compartilhado como função pública, com documentação e histórico, mesmo que ele gere somente CSS.
.dialog { @include respond(48rem) { max-width: 42rem; } }A chamada declara contexto, limite e regra local sem esconder o seletor consumidor.
Compare mixin com @extend na próxima lição. O guia de
Sass mantém a decisão maior: reusar fonte não pode tornar o CSS
gerado mais difícil de explicar.
Um último teste prático é remover o mixin mentalmente. Se duas classes comuns e
uma custom property expressam o mesmo contrato com menos indireção, escolha a
plataforma. Se cada consumidor precisa inserir um bloco dentro de uma condição
padronizada, @content oferece algo concreto. O recurso se justifica pelo
comportamento que encapsula, não pela quantidade de caracteres economizados.
Perguntas frequentes
Mixin vira uma função no CSS?
Parâmetro de mixin pode ter valor padrão?
Quando usar @content?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
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
- Sass — @mixin and @include — sass-lang.com
- Sass — At-Rules — sass-lang.com


