Vue.js: Bind de Class & Style
Última atualização: 2026-08-26
:class e :style são os dois bindings mais comumente usados no Vue — eles permitem alternar dinamicamente nomes de classes CSS e estilos inline com base nos dados. Essencialmente, são duas formas sintáticas especiais de v-bind; por serem usados com tanta frequência, foram implementados como “açúcar sintático”.
Dominar esses 5 estilos de escrita é suficiente para cobrir 95% dos cenários: sintaxe de objetos, sintaxe de matrizes, operadores ternários, propriedades calculadas e concatenação de strings.
1. O que você vai aprender
:classSintaxe de objetos: alternar entre uma única classe e várias classes com base em condições:classSintaxe de matrizes: como aplicar várias classes simultaneamente- Misturando matrizes e objetos: combinações complexas de nomes de classes
:styleSintaxe de objetos: estilos dinâmicos embutidos:styleSintaxe de matriz: mesclagem de vários objetos de estilo- Vinculação de variáveis CSS (recomendado para o Vue 3)
2. Um desafio de estilo com uma etiqueta de status do pedido
(1) Problema: 5 estados, 5 instruções “if”
Alice precisava exibir 5 status de ordem no painel de administração com cores diferentes:
<!-- ❌ The "Broken" Version: 5 v-if with class -->
<span v-if="status === 'pending'" class="badge yellow">Pending</span>
<span v-else-if="status === 'paid'" class="badge green">Paid</span>
<span v-else-if="status === 'shipped'" class="badge blue">Shipped</span>
<span v-else-if="status === 'delivered'" class="badge gray">Delivered</span>
<span v-else class="badge red">Cancelled</span>
O gerente de produto Charlie:
“Alice, isso ficou feio. E se a gente adicionar mais três status no mês que vem? Não dá pra simplesmente copiar e colar. Precisamos de uma abordagem dinâmica e organizada.”
(2) Vue :class Solução: Lidar com 5 estados em apenas 1 linha
<template>
<span :class="['badge', statusClass]">{{ statusText }}</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({ status: String })
const statusClass = computed(() => ({
pending: 'yellow',
paid: 'green',
shipped: 'blue',
delivered: 'gray',
cancelled: 'red'
}[props.status]))
const statusText = computed(() => ({
pending: 'Pending',
paid: 'Paid',
shipped: 'Shipped',
delivered: 'Delivered',
cancelled: 'Cancelled'
}[props.status]))
</script>
(3) Receita
- Redução de HTML: 5 linhas de if-else → 1 linha de :class
- Fácil de manter: Para adicionar um novo estado, basta modificar a propriedade
computed; o modelo permanece inalterado. - Legibilidade: os mapeamentos entre classes e estados estão centralizados em um único local, com uma lógica clara
3. 5 maneiras de escrever :class
(1) Sintaxe de strings
<template>
<!-- Static -->
<div class="active">Static</div>
<!-- Dynamic Strings -->
<div :class="className">Dynamic</div>
</template>
<script setup>
import { ref } from 'vue'
const className = ref('active text-bold')
</script>
(2) Sintaxe de objetos (a mais comum)
<template>
<!-- Basics: isActive is true, Add active class -->
<div :class="{ active: isActive }">Single</div>
<!-- Multiple conditions -->
<div :class="{
active: isActive,
'text-danger': hasError,
disabled: !canEdit
}">
Multiple
</div>
<!-- Computed properties return objects -->
<div :class="classObject">Computed</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
const canEdit = ref(true)
// Computed Properties:Dynamic Return class Object
const classObject = computed(() => ({
active: isActive.value && !hasError.value,
'text-danger': hasError.value,
'bg-success': isActive.value
}))
</script>
(3) Sintaxe de matrizes
<template>
<!-- Array: Several class concatenation -->
<div :class="[activeClass, errorClass]">Array</div>
<!-- Trinomial Expression -->
<div :class="[isActive ? 'active' : '', errorClass]">Ternary</div>
<!-- Array + Object Mixing -->
<div :class="[activeClass, { 'text-danger': hasError }]">Mixed</div>
<!-- Nested Objects in an Array -->
<div :class="[{ active: isActive }, errorClass]">Nested</div>
</template>
<script setup>
import { ref } from 'vue'
const activeClass = ref('active')
const errorClass = ref('text-danger')
const isActive = ref(true)
const hasError = ref(false)
</script>
(4) Coexistência com classes estáticas
<template>
<!-- Static + Dynamic Merging(Vue Automatic Merge) -->
<div class="static-class" :class="{ active: isActive }">
Both
</div>
<!-- In the end class: "static-class active" or "static-class" -->
</template>
(5) Aulas sobre componentes
<!-- Parent Component -->
<UserCard class="shadow-lg" :class="{ active: isActive }" />
<!-- Child component UserCard.vue -->
<template>
<!-- Receive -->
<div :class="$attrs.class">
<!-- Rendering "shadow-lg active" -->
</div>
</template>
4. 5 maneiras de escrever :style
(1) Sintaxe de objetos
<template>
<!-- Basic Objects -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
Object
</div>
</template>
<script setup>
import { ref } from 'vue'
const activeColor = ref('red')
const fontSize = ref(16)
</script>
(2) Conversão de nomes de propriedades CSS
O Vue converte automaticamente as convenções de nomenclatura do JavaScript para as convenções de nomenclatura do CSS:
<template>
<div :style="{
backgroundColor: 'red', // → background-color
fontSize: '16px', // → font-size
marginTop: '10px', // → margin-top
WebkitTransform: 'scale(2)' // → -webkit-transform
}">
CSS naming
</div>
</template>
(3) Sintaxe de matrizes (combinação de vários objetos)
<template>
<!-- Array:Merge style objects in order(The later one overrides the earlier one)-->
<div :style="[baseStyles, overrideStyles]">Array</div>
</template>
<script setup>
import { ref } from 'vue'
const baseStyles = ref({
color: 'blue',
fontSize: '14px'
})
const overrideStyles = ref({
color: 'red', // Coverage baseStyles.color
fontWeight: 'bold'
})
</script>
(4) Aplicação automática de prefixos
O Vue 3 adiciona automaticamente prefixos de navegador às propriedades CSS (com base no mecanismo do navegador):
// Write:
{ transform: 'rotate(45deg)' }
// Vue Auto-add:
{
-webkit-transform: 'rotate(45deg)',
transform: 'rotate(45deg)'
}
(5) Variáveis CSS (recomendado para o Vue 3)
<template>
<div :style="{
'--main-color': mainColor,
'--spacing': spacing + 'px'
}">
CSS Variables
</div>
</template>
<script setup>
import { ref } from 'vue'
const mainColor = ref('#42b883')
const spacing = ref(20)
</script>
<style>
.dynamic {
color: var(--main-color);
padding: var(--spacing);
}
</style>
5. Exemplo completo: Status dinâmico do pedido
▶ Exemplo: 1. 5 maneiras de escrever :class
<template>
<!-- 1. String -->
<div :class="className">String</div>
<!-- 2. Object -->
<div :class="{ active: isActive, error: hasError }">Object</div>
<!-- 3. Array -->
<div :class="[activeClass, errorClass]">Array</div>
<!-- 4. Array + Object -->
<div :class="[activeClass, { disabled: !canEdit }]">Mixed</div>
<!-- 5. Computed Properties -->
<div :class="dynamicClass">Computed</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
const canEdit = ref(true)
const className = ref('badge')
const activeClass = ref('active')
const errorClass = ref('error')
const dynamicClass = computed(() => ({
active: isActive.value,
error: hasError.value,
'cursor-not-allowed': !canEdit.value
}))
</script>
▶ Exemplo: 2. 5 maneiras de escrever :style
<template>
<!-- 1. Basic Objects -->
<div :style="{ color: 'red', fontSize: '16px' }">Object</div>
<!-- 2. Multiple properties -->
<div :style="{ backgroundColor: bg, padding: p + 'px' }">Multi</div>
<!-- 3. Merging Sets -->
<div :style="[baseStyles, themeStyles]">Array</div>
<!-- 4. CSS Variable -->
<div :style="{ '--theme-color': theme }">CSS Var</div>
<!-- 5. Computed Properties -->
<div :style="computedStyle">Computed</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const bg = ref('#42b883')
const p = ref(20)
const theme = ref('#35495e')
const baseStyles = ref({ color: 'white' })
const themeStyles = ref({ backgroundColor: '#42b883' })
const computedStyle = computed(() => ({
color: 'white',
backgroundColor: theme.value,
padding: `${p.value}px`
}))
</script>
▶ Exemplo: 3. Emblema de status do pedido
<template>
<span :class="['order-badge', statusClass]">
{{ statusText }}
</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
status: { type: String, required: true }
})
// 5 Status → 5 class
const statusClass = computed(() => {
const map = {
pending: 'bg-yellow',
paid: 'bg-green',
shipped: 'bg-blue',
delivered: 'bg-gray',
cancelled: 'bg-red'
}
return map[props.status] || 'bg-default'
})
const statusText = computed(() => {
const map = {
pending: 'Pending',
paid: 'Paid',
shipped: 'Shipped',
delivered: 'Delivered',
cancelled: 'Cancelled'
}
return map[props.status] || 'Unknown'
})
</script>
<style scoped>
.order-badge {
padding: 4px 12px;
border-radius: 12px;
color: white;
font-size: 12px;
}
.bg-yellow { background: #f59e0b; }
.bg-green { background: #10b981; }
.bg-blue { background: #3b82f6; }
.bg-gray { background: #6b7280; }
.bg-red { background: #ef4444; }
</style>
▶ Exemplo: 4. 5 erros comuns
| Erro | Sintoma | Solução |
|---|---|---|
| A classe String não está respondendo | A classe está codificada de forma rígida e não muda | Vinculada usando :class |
| Nome incorreto da classe de array | Várias classes com o mesmo nome se sobrescrevendo mutuamente | Uso da sintaxe de objeto |
| Unidade de estilo ausente | O número 16 é interpretado como 16px e é ignorado | A sequência de caracteres '16px' é exibida |
| Nome incorreto da propriedade CSS | font-size deveria ser fontSize |
Use camelCase ou aspas |
| :conflito de classe | Colisão de nomes estáticos e dinâmicos | O Vue os mescla automaticamente, tudo bem |
▶ Exemplo: 5. 5 Comparações de desempenho
| Implementação | Resultado da compilação | Desempenho | Aplicabilidade |
|---|---|---|---|
| String | Concatenação direta de strings | ⭐⭐⭐⭐⭐ | Simples |
| Objeto | Análise estática | ⭐⭐⭐⭐ | Moderado |
| Matrizes | Concatenação de strings | ⭐⭐⭐⭐ | Várias classes |
| Matrizes + Objetos | Tratamento misto | ⭐⭐⭐ | Complexo |
| Propriedade calculada | Valor armazenado em cache | ⭐⭐⭐⭐⭐ | Lógica complexa |
▶ Exemplo: 6. As 5 principais diferenças entre classe e estilo
| Aspecto | classe | estilo |
|---|---|---|
| Avaliação | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| Reutilização de CSS | Fácil (reutilização de nomes de classes) | Difícil (estilos dispersos) |
| Desempenho | Superior (otimização do navegador) | Ligeiramente inferior |
| Prioridade | Depende do seletor | Em linha (mais alta) |
| Troca de tema | Fácil (alterar classe) | Fácil (alterar variável CSS) |
❓ Perguntas Frequentes
P: As ligações de classe e de estilo podem coexistir? R: Sim. As ligações estáticas
class="x"e dinâmicas:class="{active: y}"são automaticamente combinadas (resultando em class="x active" ou "x").
P: Por que o atributo
styleprecisa ser escrito como um objeto? Não posso simplesmente usar uma string de CSS? R: Sim, você pode.<div style="color: red">é a sintaxe nativa do HTML, e<div :style="'color: red'">também é uma abordagem baseada em string. No entanto, usar um objeto:style="{ color: 'red' }"permite que você vincule variáveis dinamicamente. Recomendamos o uso de um objeto.
P: Como se usa variáveis CSS? R: Use
{'--my-var': value}em:styleevar(--my-var)no CSS. O Vue 3 recomenda o uso de variáveis CSS para a troca de temas, pois é mais eficiente do que vincular estilos diretamente (basta atualizar uma única variável, e o DOM não será reajustado).
P: Como os componentes recebem classes externas? R: Os componentes de raiz única herdam automaticamente o atributo
class(comportamento padrão do Vue 3). Os componentes de raízes múltiplas usam$attrs.classpara se vincular explicitamente a um elemento específico.
P: Qual é a ordem das classes na sintaxe de array? R: Elas são concatenadas na ordem em que aparecem no array, mas a ordem não afeta a especificidade do CSS (que é determinada pela especificidade dos seletores CSS).
P: É possível usar :class com v-if? R: Sim.
<div v-if="show" :class="{ active: isActive }">Quando show=false, o elemento inteiro não é renderizado, e isActive não tem efeito.
P: Como faço para alternar temas dinamicamente? R: Recomendamos o uso de variáveis CSS.
:style="{ '--primary': theme.primary }"se aplica a todos os elementoscolor: var(--primary). Para alternar temas, basta alterar apenas uma variável, o que é mais eficiente do que alterar 100 classes.
📖 Resumo
:classe:stylesão sinônimos sintáticos de v-bind; como são os mais utilizados, foram simplificados.- :class — 5 maneiras de defini-la: string, objeto, array, array + objeto, propriedade calculada
- :style — 5 maneiras de escrevê-lo: objeto, array, array + objeto, variáveis CSS, propriedades calculadas
- Fusão automática de classes estáticas e dinâmicas :class
- O Vue 3 adiciona automaticamente prefixos de CSS para navegadores
- As variáveis CSS são a solução recomendada para a troca de temas no Vue 3 (mais eficiente do que trocar estilos)
- Desempenho: Propriedades de objeto/computadas > Matrizes > Strings
📝 Exercícios
-
Questões básicas (Dificuldade: ⭐)
Use o seletor :class para implementar três estados do botão:
- principal: texto branco sobre fundo azul
- sucesso: texto branco sobre fundo verde
- perigo: texto branco sobre fundo vermelho
Dados:
const variant = ref('primary') -
Problemas avançados (Dificuldade: ⭐⭐)
Implemente uma lista de pedidos em que cada linha exiba um ícone em uma cor diferente, de acordo com o status do pedido:
- 5 status (em espera/pago/enviado/entregue/cancelado)
- Retornar um objeto
classusando uma propriedade calculada - :style Adicione a cor do ícone correspondente ao status
-
Problema desafiador (Dificuldade: ⭐⭐⭐)
Implementar um sistema completo de troca de temas:
- 3 temas (claro/escuro/alto contraste)
- Use variáveis CSS para definir as cores do tema (primária/secundária/fundo/texto)
- :class — Alterar o nome da classe do tema
- Use o localStorage para lembrar a seleção do usuário
- A troca de temas não atualiza a página (o design responsivo é atualizado automaticamente)