# Efeito hover com gradiente em CSS: quatro formas de animar

[Canonical HTML page](https://gradiently.design/pt-br/guide/css-hover-gradient)

Escreva um novo gradiente no :hover e ele troca de uma vez, sem suavidade. Os navegadores não fazem transição de um gradiente para outro, mas conseguem movê-lo, esmaecê-lo ou animar as cores dentro dele. Aqui está cada método, com o código.

## The short version

- Um efeito hover com gradiente em CSS não sai com uma transição de background-image, porque os navegadores trocam gradientes na hora em vez de interpolá-los.
- A técnica mais compatível é um gradiente maior que o elemento com transição em background-position, que desliza as novas cores para a vista.
- Registrar paradas de cor ou ângulos com @property permite que o navegador faça a transição suavemente, e funciona em todos os principais navegadores atuais.
- Esmaecer a opacidade de um segundo gradiente num pseudo-elemento é a técnica mais barata de renderizar, porque mudanças de opacidade não exigem repintura.
- Efeitos hover devem ficar dentro de uma media query de hover e respeitar prefers-reduced-motion.

Um **efeito hover com gradiente em CSS** exige um contorno, porque os navegadores não fazem transição de `background-image`: mude o gradiente no `:hover` e ele troca de uma vez. Quatro técnicas dão um resultado suave. Deslizar um gradiente maior que o elemento com `background-position`, animar paradas de cor registradas com `@property`, fazer crossfade de um segundo gradiente num pseudo-elemento ou mover um brilho radial junto com o cursor. Cada uma serve para elementos diferentes, e todas estão abaixo com código.

## Por que transition não funciona em gradientes

Para o navegador, um gradiente é uma imagem. Ele sabe interpolar um número ou uma cor, mas não uma imagem em outra, então `background-image` não é interpolado e o novo gradiente substitui o antigo instantaneamente. Propriedades personalizadas usadas dentro do gradiente se comportam do mesmo jeito, a menos que você as registre, porque uma propriedade não registrada é só texto.

```css
/* This snaps, with no easing */
.btn {
  background-image: linear-gradient(135deg, #1e1b4b, #6d28d9);
  transition: background-image 400ms ease;
}
.btn:hover {
  background-image: linear-gradient(135deg, #6d28d9, #f472b6);
}
```

A linha de transition é ignorada para gradientes. Todas as técnicas abaixo contornam isso.

- Estado em repouso: `linear-gradient(135deg, #1e1b4b 0%, #6d28d9 100%)`
- Estado no hover: `linear-gradient(135deg, #6d28d9 0%, #f472b6 100%)`

Os dois estados usados nos exemplos. O objetivo é uma passagem suave da amostra da esquerda para a da direita.

## Técnica 1: deslizar um gradiente maior

Deixe o fundo maior que o elemento, pinte os dois estados nele e depois mova-o. `background-position` aceita transição, então as novas cores deslizam para dentro. Funciona em todos os navegadores e não precisa de registro.

```css
.btn {
  background-image: linear-gradient(90deg, #1e1b4b 0%, #6d28d9 50%, #f472b6 100%);
  background-size: 200% 100%;
  background-position: 0% 50%;
  transition: background-position 500ms ease;
}

.btn:hover {
  background-position: 100% 50%;
}
```

Em repouso você vê a metade esquerda, do índigo ao violeta. No hover, a metade direita, do violeta ao rosa, desliza para o lugar.

A faixa inteira de 200%: `linear-gradient(90deg, #1e1b4b 0%, #6d28d9 50%, #f472b6 100%)`

Este é o fundo inteiro. O botão só mostra metade dele por vez.

O movimento parece uma varredura, o que combina com botões e links. É menos convincente em cards grandes, onde dá para ver o gradiente viajando. Animar `background-position` exige repintura, o que tudo bem em elementos pequenos; para uma superfície grande, use a técnica 3. [Botões com gradiente em CSS](https://gradiently.design/pt-br/guide/css-gradient-button) traz mais padrões de botão baseados nisso.

## Técnica 2: animar paradas de cor com @property

Registre as cores das paradas como propriedades personalizadas tipadas e o navegador consegue interpolá-las. O gradiente então muda de cor no lugar, sem deslizar. `@property` funciona em todos os principais navegadores atuais; os mais antigos simplesmente trocam de uma vez, o que é uma alternativa aceitável para um hover. As regras de registro estão em [CSS @property](https://gradiently.design/pt-br/guide/css-property-animation).

```css
@property --stop-a {
  syntax: "<color>";
  inherits: false;
  initial-value: #1e1b4b;
}

@property --stop-b {
  syntax: "<color>";
  inherits: false;
  initial-value: #6d28d9;
}

.card {
  background-image: linear-gradient(135deg, var(--stop-a), var(--stop-b));
  transition: --stop-a 450ms ease, --stop-b 450ms ease;
}

.card:hover {
  --stop-a: #6d28d9;
  --stop-b: #f472b6;
}
```

Cada parada suaviza de forma independente. Dê durações diferentes a elas e a cor parece fluir de um canto ao outro.

O mesmo truque anima o ângulo. Registre `--angle` com `syntax: "<angle>"`, use-o em `linear-gradient(var(--angle), ...)` e mude-o no hover: um gradiente que gira de 135 para 225 graus quando o ponteiro chega é um toque sutil e refinado para cards e [bordas com gradiente](https://gradiently.design/pt-br/guide/css-gradient-border).

As duas técnicas até aqui também funcionam em [texto com gradiente](https://gradiently.design/pt-br/guide/css-gradient-text). Texto recortado com `background-clip: text` mostra o que o fundo fizer, então um deslize ou uma transição de paradas num título faz a cor correr pelas letras no hover. Mantenha a mudança suave em títulos que as pessoas precisam ler e garanta que os dois estados tenham contraste com a página.

## Técnica 3: crossfade entre dois gradientes

Coloque o gradiente do hover num pseudo-elemento acima da base e esmaeça a opacidade dele. Mudanças de opacidade são tratadas pelo compositor sem repintura, então esta é a escolha mais suave para cards grandes, painéis de hero e qualquer coisa numa grade longa.

```css
.tile {
  position: relative;
  isolation: isolate;
  background-image: linear-gradient(135deg, #1e1b4b, #6d28d9);
}

.tile::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-image: linear-gradient(135deg, #6d28d9, #f472b6);
  opacity: 0;
  transition: opacity 400ms ease;
}

.tile:hover::before {
  opacity: 1;
}
```

`z-index: -1` com `isolation: isolate` mantém o pseudo-elemento atrás do texto do bloco, mas acima do gradiente de base.

## Técnica 4: um brilho que segue o cursor

Um gradiente radial posicionado com propriedades personalizadas pode acompanhar o ponteiro. Defina `--x` e `--y` com um pequeno script e a luz se move com a mão. Mantenha-o suave e longe do texto: deve parecer luz sobre uma superfície, nunca um halo em volta das palavras.

```css
.panel {
  background-image:
    radial-gradient(circle 220px at var(--x, 50%) var(--y, 50%), rgb(244 114 182 / 0.35), transparent 70%),
    linear-gradient(135deg, #1e1b4b, #312e81);
}

/* JavaScript:
   panel.addEventListener("pointermove", (e) => {
     const r = panel.getBoundingClientRect();
     panel.style.setProperty("--x", `${e.clientX - r.left}px`);
     panel.style.setProperty("--y", `${e.clientY - r.top}px`);
   });
*/
```

O brilho é uma camada superior sobre uma base escura. Atualizar duas propriedades personalizadas é barato, mas cada movimento repinta, então use em poucos painéis, não em todos os cards da página.

## Como escolher a técnica

| Técnica | Aparência | Custo de renderização | Ideal para |
| --- | --- | --- | --- |
| Deslize com background-position | Uma varredura de cor nova | Repinta durante a transição | Botões, links, tags |
| Paradas de cor com @property | Cores mudando no lugar | Repinta durante a transição | Cards, selos, bordas |
| Crossfade de opacidade | Um gradiente se dissolvendo em outro | Composto, sem repintura | Painéis grandes, grades longas |
| Brilho no cursor | Luz seguindo o ponteiro | Repinta a cada movimento | Alguns painéis de destaque |

Na dúvida, use crossfade. É o mais barato e funciona em todo lugar.

Para gradientes que se movem sozinhos, e não no hover, veja [gradientes animados em CSS](https://gradiently.design/pt-br/guide/css-animated-gradient). Para um panorama do que custa tempo de pintura, veja [desempenho de gradientes CSS](https://gradiently.design/pt-br/guide/css-gradient-performance).

## Telas sensíveis ao toque e movimento reduzido

### Evite

- Estilos de hover que ficam presos depois de um toque no celular
- Informações que só aparecem no hover
- Animações de hover longas e em loop
- Ignorar a configuração de movimento reduzido

### Faça

- Envolva as regras de hover em `@media (hover: hover)`
- Mostre o mesmo estado em `:active` para toque
- Mantenha as transições entre 200 e 500ms
- Corte o movimento sob `prefers-reduced-motion` e mantenha a mudança de cor

```css
@media (hover: hover) {
  .btn:hover { background-position: 100% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
}
```

A cor continua mudando para todo mundo; só o movimento sai para quem pediu menos.

Efeitos hover dão vida a um site. Em posts de redes sociais não há ponteiro, então o movimento precisa viver no próprio design. Os Marks do Gradiently podem ter seu próprio movimento suave e, com o Pro, um design é exportado como MP4, WebM ou GIF onde o navegador permite gravar, pronto para um story ou um post.

## FAQ

### Dá para fazer transição de um gradiente CSS no hover?

Não diretamente. `background-image` muda na hora. Faça a transição de `background-position` num gradiente maior, anime paradas registradas com `@property` ou esmaeça a opacidade de um segundo gradiente.

### Como faço um botão com gradiente mudar de cor suavemente no hover?

Use `background-size: 200% 100%` com um gradiente de três paradas e faça a transição de `background-position` de `0% 50%` para `100% 50%` no hover.

### O @property funciona em todos os navegadores?

Funciona nas versões atuais do Chrome, Edge, Safari e Firefox. Navegadores antigos trocam de estado de uma vez, sem suavizar.

### Qual é o efeito hover com gradiente de melhor desempenho?

Um crossfade de opacidade: o gradiente do hover fica num pseudo-elemento e só a opacidade dele muda, o que evita repintura.

### Efeitos hover com gradiente devem respeitar o movimento reduzido?

Sim. Sob `prefers-reduced-motion: reduce`, remova o movimento e mantenha uma mudança de cor simples.
