# Gradientes SVG: lineares, radiais, contornos, texto e máscaras

[Canonical HTML page](https://gradiently.design/pt-pt/guide/svg-gradients)

O SVG tem o seu próprio sistema de gradientes, mais antigo do que os gradientes CSS e capaz de coisas que eles não conseguem: colorir um contorno, preencher uma palavra, partilhar um gradiente por várias formas e esbater qualquer coisa com uma máscara.

## The short version

- Um gradiente SVG define-se uma vez como um elemento linearGradient ou radialGradient com filhos stop, recebe um id e aplica-se com fill ou stroke definidos como url(#id).
- Por omissão, as coordenadas dos gradientes SVG usam unidades objectBoundingBox, em que 0 e 1 são as margens da forma que está a ser pintada.
- gradientUnits="userSpaceOnUse" coloca o gradiente nas coordenadas do próprio desenho, o que permite que um gradiente abranja várias formas e corrige os gradientes em linhas perfeitamente retas.
- spreadMethod decide o que acontece para lá das pontas do gradiente: pad mantém as cores das pontas, reflect espelha a mistura e repeat recomeça-a.
- Uma máscara SVG usa a luminosidade, por isso um gradiente de branco a preto dentro de uma máscara esbate aquilo a que for aplicado.

Um **gradiente SVG** é uma tinta que defines uma vez e aplicas a qualquer forma, linha ou texto num SVG. Escreves um elemento `<linearGradient>` ou `<radialGradient>` dentro de `<defs>`, dás-lhe filhos `<stop>` para as cores e um `id`, e depois defines o `fill` ou o `stroke` de uma forma como `url(#id)`. Ao contrário de um fundo CSS, pode colorir um contorno ou uma única palavra, e acompanha a escala do desenho.

```html
<svg viewBox="0 0 200 120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="dusk" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="#1e1b4b" />
      <stop offset="0.55" stop-color="#7c3aed" />
      <stop offset="1" stop-color="#f472b6" />
    </linearGradient>
  </defs>
  <rect width="200" height="120" rx="16" fill="url(#dusk)" />
</svg>
```

Um gradiente diagonal num retângulo arredondado. x1, y1, x2 e y2 traçam a linha do gradiente do canto superior esquerdo ao inferior direito.

A mesma mistura, em CSS: `linear-gradient(135deg, #1e1b4b 0%, #7c3aed 55%, #f472b6 100%)`

O SVG acima e este gradiente CSS coincidem num quadrado. Num retângulo, a versão SVG estica-se com a forma; vê gradientUnits mais abaixo.

## linearGradient e as suas paragens

`x1`, `y1`, `x2` e `y2` definem o início e o fim da linha do gradiente. Cada `<stop>` recebe um `offset` de 0 a 1 (ou de 0% a 100%), um `stop-color` e um `stop-opacity` opcional. `stop-color` também é uma propriedade CSS, por isso podes dar tema aos gradientes a partir de uma folha de estilos, por exemplo `stop { stop-color: var(--accent); }`.

| Atributo | Por omissão | O que faz |
| --- | --- | --- |
| `x1 y1 x2 y2` | `0 0 1 0`, da esquerda para a direita | Pontos de início e de fim da linha do gradiente |
| `gradientUnits` | `objectBoundingBox` | Se as coordenadas são relativas à forma ou ao desenho |
| `spreadMethod` | `pad` | O que acontece para lá das pontas: `pad`, `reflect` ou `repeat` |
| `gradientTransform` | nenhum | Roda, escala ou inclina o gradiente, por exemplo `rotate(30)` |
| `href` | nenhum | Herda paragens e definições de outro gradiente |

Os principais atributos de linearGradient. radialGradient partilha todos menos a primeira linha.

`href` poupa repetição. Define as tuas paragens uma vez num gradiente base e depois cria variações que apontam para ele e mudam só a direção ou as unidades. A [referência de linearGradient na MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient) explica todos os atributos.

## radialGradient: centro, raio e ponto focal

Um gradiente radial recebe um centro (`cx`, `cy`) e um raio (`r`), todos com 0.5 por omissão, por isso preenche a forma a partir do meio. Tem também algo que falta ao CSS: um ponto focal separado (`fx`, `fy`) onde começa a primeira cor. Deslocar o ponto focal para fora do centro faz uma esfera parecer iluminada de um lado.

```html
<radialGradient id="orb" cx="0.5" cy="0.5" r="0.5" fx="0.32" fy="0.28">
  <stop offset="0" stop-color="#e0f2fe" />
  <stop offset="0.45" stop-color="#0ea5e9" />
  <stop offset="1" stop-color="#082f49" />
</radialGradient>

<circle cx="60" cy="60" r="50" fill="url(#orb)" />
```

Um ponto focal para cima e para a esquerda transforma um círculo liso numa esfera brilhante.

Esfera iluminada, aproximada em CSS: `radial-gradient(circle at 32% 28%, #e0f2fe, #0ea5e9 35%, #082f49 80%)`

O CSS consegue mover o centro, mas não separar centro e foco, por isso isto é só uma aproximação da esfera SVG. Compara com [gradientes radiais em CSS](https://gradiently.design/pt-pt/guide/css-radial-gradient).

## gradientUnits: objectBoundingBox ou userSpaceOnUse

Com o valor por omissão `objectBoundingBox`, 0 e 1 significam as margens da forma que estiver a ser pintada, por isso cada forma recebe o gradiente inteiro, esticado para caber. Com `userSpaceOnUse`, as coordenadas estão nas unidades do próprio SVG, por isso o gradiente fica parado e as formas revelam a parte dele que cobrem. É assim que uma fila de barras pode partilhar um gradiente contínuo.

### objectBoundingBox

- Coordenadas de 0 a 1 ao longo de cada forma
- Cada forma mostra o gradiente completo
- O gradiente estica-se com as proporções da forma
- Falha numa linha perfeitamente horizontal ou vertical

### userSpaceOnUse

- Coordenadas nas unidades do próprio desenho
- As formas revelam a sua fatia de um só gradiente
- Os ângulos mantêm-se certos seja qual for a forma
- Funciona em linhas retas e contornos finos

> **A linha reta invisível** Uma `<line>` horizontal tem uma caixa delimitadora de altura zero, e as unidades da caixa delimitadora não se podem calcular a partir de zero, por isso um contorno com gradiente por omissão não desenha nada. Define `gradientUnits="userSpaceOnUse"` e dá coordenadas reais.

## Gradientes em contornos e em texto

`stroke="url(#id)"` pinta contornos, e é assim que se desenham ícones com gradiente, anéis de progresso e linhas de gráficos. Em `<text>`, `fill="url(#id)"` colore as letras, e as palavras continuam selecionáveis e pesquisáveis. Junta uma cor lisa depois do URL, como `fill="url(#dusk) #7c3aed"`, e ela é usada se o gradiente não for encontrado.

```html
<svg viewBox="0 0 320 120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="line" gradientUnits="userSpaceOnUse" x1="20" y1="0" x2="300" y2="0">
      <stop offset="0" stop-color="#22d3ee" />
      <stop offset="1" stop-color="#a855f7" />
    </linearGradient>
  </defs>
  <path d="M20 90 C 90 20, 160 110, 300 30" fill="none" stroke="url(#line)" stroke-width="6" stroke-linecap="round" />
  <text x="20" y="115" font-size="20" font-weight="700" fill="url(#line) #7c3aed">Growth</text>
</svg>
```

Um gradiente em unidades do desenho, partilhado por uma curva e uma palavra. Ambas vão do ciano ao roxo ao longo da mesma extensão horizontal.

Para letras com gradiente em HTML e não em SVG, [texto com gradiente em CSS](https://gradiently.design/pt-pt/guide/css-gradient-text) é normalmente mais simples. Recorre ao texto SVG quando as palavras fazem parte de uma ilustração ou de um logótipo, ou precisam de seguir um traçado.

## spreadMethod: pad, reflect e repeat

Quando a linha do gradiente é mais curta do que a forma, `spreadMethod` decide o que preenche o resto. `pad` mantém as cores das pontas, `reflect` espelha a mistura para trás e para a frente e `repeat` recomeça-a com uma aresta nítida. Aqui cada gradiente vai de 30% a 70% da largura.

- pad: `linear-gradient(90deg, #0f766e 30%, #fde68a 70%)`
- reflect: `repeating-linear-gradient(90deg, #fde68a -10%, #0f766e 30%, #fde68a 70%)`
- repeat: `repeating-linear-gradient(90deg, #0f766e 30%, #fde68a 70%)`

Do azul-petróleo à areia com os três métodos de extensão, reproduzidos em CSS para os comparares lado a lado.

## Esbater com máscaras SVG

Uma máscara usa a luminosidade: as áreas brancas mostram o que está mascarado, as pretas escondem-no e os cinzentos ficam no meio. Assim, um gradiente de branco a preto dentro de uma `<mask>` esbate suavemente qualquer forma ou imagem até ao nada, e é assim que se suaviza a margem de uma foto ou se faz uma linha de gráfico desaparecer no início.

```html
<defs>
  <linearGradient id="fade" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0.4" stop-color="#fff" />
    <stop offset="1" stop-color="#000" />
  </linearGradient>
  <mask id="soft-bottom">
    <rect width="100%" height="100%" fill="url(#fade)" />
  </mask>
</defs>

<image href="photo.jpg" width="100%" height="100%" mask="url(#soft-bottom)" />
```

A foto está totalmente visível no topo e esbate-se ao longo dos 60% inferiores.

Em elementos HTML, o CSS `mask-image: linear-gradient(#000 40%, transparent)` faz o mesmo trabalho, usando o alfa em vez da luminosidade. A técnica da máscara também está por trás dos [contornos com gradiente em CSS](https://gradiently.design/pt-pt/guide/css-gradient-border) transparentes.

### Evita

- Reutilizar o mesmo `id` de gradiente em dois SVG inline na mesma página
- Esconder um sprite de definições de gradientes com `display: none`
- Unidades por omissão em linhas retas
- Gradientes muito longos, suaves e escuros sem textura

### Faz

- Ids únicos, ou um só sprite de definições partilhado
- Esconde os sprites com largura e altura zero
- `userSpaceOnUse` para contornos e gradientes partilhados
- Junta grão aos esbatidos grandes, vê [textura de ruído em CSS](https://gradiently.design/pt-pt/guide/css-noise-texture)

## FAQ

### Como junto um gradiente a um SVG?

Define um `<linearGradient>` ou `<radialGradient>` com filhos `<stop>` e um `id` dentro de `<defs>`, e depois define o `fill` ou o `stroke` de uma forma como `url(#id)`.

### Porque é que o contorno com gradiente SVG não aparece numa linha?

Uma linha reta horizontal ou vertical tem uma caixa delimitadora de tamanho zero, por isso as unidades `objectBoundingBox` por omissão falham. Usa `gradientUnits="userSpaceOnUse"` com coordenadas reais.

### Como rodo um gradiente SVG?

Altera `x1`, `y1`, `x2` e `y2`, ou junta `gradientTransform="rotate(45 0.5 0.5)"` para rodar em torno do centro da caixa delimitadora.

### Posso mudar as cores de um gradiente SVG com CSS?

Sim. `stop-color` e `stop-opacity` são propriedades CSS, por isso regras como `stop { stop-color: var(--accent); }` funcionam em SVG inline.

### Porque é que o meu gradiente SVG desapareceu quando escondi o SVG?

As definições dentro de um SVG com `display: none` podem não ser desenhadas. Esconde antes o sprite com largura e altura zero, ou com posicionamento absoluto.
