Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIntermediáriocódigo testado

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.

Rodolfo Mori5 min de leitura

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:

css
@mixin focus-ring {
  outline: 3px solid #a78bfa;
  outline-offset: 2px;
}

.button:focus-visible { @include focus-ring; }
.button:focus-visible { outline: 3px solid #a78bfa; outline-offset: 2px; }

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:

css
@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); }
.save { background: #6d28d9; color: white; border-radius: 0.5rem; } .cancel { background: #e5e7eb; color: #111827; border-radius: 0.5rem; }

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:

css
@mixin badge($bg, $color) {
  background: $bg;
  color: $color;
}

.badge { @include badge(#dc2626); }
Error: Missing argument $color. ╷ 1 │ @mixin badge($bg, $color) { │ ━━━━━━━━━━━━━━━━━━ declaration ... │ 6 │ .badge { @include badge(#dc2626); } │ ^^^^^^^^^^^^^^^^^^^^^^^ invocation ╵ missing-argument.scss 6:10 badge() missing-argument.scss 6:10 root stylesheet

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:

css
.card {
  @include flex-centro;
}
Error: Undefined mixin. ╷ 2 │ @include flex-centro; │ ^^^^^^^^^^^^^^^^^^^^ ╵ undefined-mixin.scss 2:3 root stylesheet

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:

css
@mixin respond($width) {
  @media (min-width: $width) { @content; }
}

.grid {
  display: grid;
  @include respond(48rem) {
    grid-template-columns: 1fr 1fr;
  }
}
.grid { display: grid; } @media (min-width: 48rem) { .grid { 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:

css
@mixin theme($name) {
  [data-theme="#{$name}"] & { @content; }
}

.card {
  @include theme(dark) {
    background: #111827;
    color: white;
  }
}
[data-theme=dark] .card { 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:

css
@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); }
.arrow { width: 0; height: 0; border: 8px solid transparent; border-bottom-color: #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:

css
@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:

bash
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 -c
40 279 3670 mixin-40.css 216

O 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.

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.

  • sass
  • mixin
  • include
  • content
  • breakpoints
  • reuso

Perguntas frequentes

Mixin vira uma função no CSS?
Não. Cada @include emite declarações ou regras concretas. O navegador não recebe o mixin nem executa Sass.
Parâmetro de mixin pode ter valor padrão?
Sim. Escreva $nome: valor na declaração. Argumentos nomeados tornam chamadas com vários opcionais mais fáceis de ler.
Quando usar @content?
Quando o mixin fornece um contexto, como media query ou tema, e o chamador precisa entregar o bloco de regras que ficará dentro dele.

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 — @mixin and @include — sass-lang.com
  2. Sass — At-Rules — sass-lang.com

Continue por aqui