Gradiente SVG usando CSS

102

Estou tentando aplicar um gradiente a um rectelemento SVG .

Atualmente, estou usando o fillatributo. No meu arquivo CSS:

rect {
    cursor: pointer;
    shape-rendering: crispEdges;
    fill: #a71a2e;
}

E o rectelemento tem a cor de preenchimento correta quando visualizado no navegador.

No entanto, gostaria de saber se posso aplicar um gradiente linear a este elemento.

Hrishikesh Choudhari
fonte

Respostas:

95

Apenas use no CSS o que você usaria em um fillatributo. Obviamente, isso requer que você tenha definido o gradiente linear em algum lugar do seu SVG.

Aqui está um exemplo completo:

rect {
    cursor: pointer;
    shape-rendering: crispEdges;
    fill: url(#MyGradient);
}
<svg width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
      <style type="text/css">
        rect{fill:url(#MyGradient)}
      </style>
      <defs>
        <linearGradient id="MyGradient">
          <stop offset="5%" stop-color="#F60" />
          <stop offset="95%" stop-color="#FF6" />
        </linearGradient>
      </defs>
      
      <rect width="100" height="50"/>
    </svg>

Thomas W
fonte
2
Então, eu criei esse gradiente em um arquivo separado, e usado filldesta forma: fill: url(../js/gradient.svg#MyGradient);. Este é o caminho certo?
Hrishikesh Choudhari
@HrishikeshChoudhari: Sim, está correto, mas o Chrome e eu acho que o Safari também não oferece suporte a elementos de referência de outros arquivos. Não tenho certeza sobre o IE9 (não é possível testar agora, apenas experimente).
Thomas W
53
Para quem lê isso e pergunta "sobre o quê fill: linear-gradient (...)?" fillrequer um <paint>que é construído em torno da <color>classe CSS2 . Em outras palavras, esta resposta é atualmente a única maneira de fazer isso via CSS no momento em que escrevo este comentário. Você precisa adicionar um linearGradientelemento. Por último, examinando o W3 Working Draft para SVG2 , parece que o suporte para linear-gradienta regra de preenchimento de css não foi e pode não entrar na especificação.
Arthur Weborg
Como mudar a direção neste caso?
AGamePlayer de
1
@AwQiruiGuo Dê uma olhada no MDN (especificamente o gradientTransformatributo)
Thomas W
34

Resposta 2019

Com novas propriedades de css, você pode ter ainda mais flexibilidade com variáveis ​​também conhecidas como custom properties

.shape {
  width:500px;
  height:200px;
}

.shape .gradient-bg {
  fill: url(#header-shape-gradient) #fff;
}

#header-shape-gradient {
  --color-stop: #f12c06;
  --color-bot: #faed34;
}
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" class="shape">
  <defs>
    <linearGradient id="header-shape-gradient" x2="0.35" y2="1">
        <stop offset="0%" stop-color="var(--color-stop)" />
        <stop offset="30%" stop-color="var(--color-stop)" />
        <stop offset="100%" stop-color="var(--color-bot)" />
      </linearGradient>
  </defs>
  <g>
    <polygon class="gradient-bg" points="0,0 100,0 0,66" />
  </g>
</svg>

Basta definir uma variável nomeada para cada stopgradiente e, em seguida, personalizar como quiser em css. Você pode até mesmo alterar seus valores dinamicamente com javascript, como:

document.querySelector('#header-shape-gradient').style.setProperty('--color-stop', "#f5f7f9");
Maciej Kwas
fonte
3
Não compatível com o IE.
Aoakeson,
3
As propriedades personalizadas do CSS estão aqui há muito tempo, se de alguma forma alguém ainda não estiver pronto para usá-las, ele nunca estará pronto para mudanças.
Maciej Kwas 01 de
1
@MaciejKwas, você está errado. Os navegadores antigos não duram para sempre, então as empresas que não estão prontas agora estarão prontas então. E se alguém não está pronto para descartar uma parte de seu público, isso não significa que ele não está pronto para mudanças, significa que ele prefere aproveitar as mudanças mais tarde para manter um público maior.
Finesse
19
@aoakeson IE está morto. Fim da vida. O Edge também está morrendo, essa é uma resposta de 2019, então o IE não deveria contar. O IE pode degradar normalmente usando uma cor sólida.
Ciprian
5
@aoakeson Estou incrivelmente surpreso de encontrar esse tipo de resposta em 2019. Você seria ingênuo como desenvolvedor ao presumir que o suporte SVG no IE neste nível jamais seria suportado, muito menos um desenvolvedor iniciante no SO dando a você um , resposta polyfilled para algo desnecessariamente necessário se você pretende oferecer suporte ao IE.
James Martin-Davies
18

Construindo em cima do que Finesse escreveu, aqui está uma maneira mais simples de direcionar o svg e alterar seu gradiente.

Isso é o que você precisa fazer:

  1. Atribua classes a cada interrupção de cor definida no elemento de gradiente.
  2. Mire o css e altere a cor de parada para cada uma dessas paradas usando classes simples.
  3. Ganhar!

Alguns benefícios de usar classes em vez de :nth-childé que isso não será afetado se você reordenar suas paradas. Além disso, torna a intenção de cada classe clara - você ficará se perguntando se precisava de uma cor azul na primeira criança ou na segunda.

Eu testei em todos os Chrome, Firefox e IE11:

.main-stop {
  stop-color: red;
}
.alt-stop {
  stop-color: green;
}
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <linearGradient id="gradient">
    <stop class="main-stop" offset="0%" />
    <stop class="alt-stop" offset="100%" />
  </linearGradient>
  <rect width="100" height="50" fill="url(#gradient)" />
</svg>

Veja um exemplo editável aqui: https://jsbin.com/gabuvisuhe/edit?html,css,output

Kumarharsh
fonte
A falta é que você não sabe ao certo quais são os nomes das classes de parada e em que ordem eles têm. Na verdade, as soluções são as mesmas boas, a única diferença são os seletores de CSS.
Finesse
3
Acho que esta é a melhor resposta moderna para a pergunta dos OPs.
Elemental de
9

Aqui está uma solução em que você pode adicionar um gradiente e alterar suas cores usando apenas CSS:

// JS is not required for the solution. It's used only for the interactive demo.
const svg = document.querySelector('svg');
document.querySelector('#greenButton').addEventListener('click', () => svg.setAttribute('class', 'green'));
document.querySelector('#redButton').addEventListener('click', () => svg.setAttribute('class', 'red'));
svg.green stop:nth-child(1) {
  stop-color: #60c50b;
}
svg.green stop:nth-child(2) {
  stop-color: #139a26;
}

svg.red stop:nth-child(1) {
  stop-color: #c84f31;
}
svg.red stop:nth-child(2) {
  stop-color: #dA3448;
}
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <linearGradient id="gradient">
    <stop offset="0%" />
    <stop offset="100%" />
  </linearGradient>
  <rect width="100" height="50" fill="url(#gradient)" />
</svg>

<br/>
<button id="greenButton">Green</button>
<button id="redButton">Red</button>

Finesse
fonte
2

Obrigado a todos, por todas as suas respostas precisas.

Usando o svg em um shadow dom, adiciono os 3 gradientes lineares de que preciso dentro do svg, dentro de a. Eu coloco a regra de preenchimento de css no componente da web e a herança de preenchimento faz o trabalho.

<svg viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
  <path
    d="m258 0c-45 0-83 38-83 83 0 45 37 83 83 83 45 0 83-39 83-84 0-45-38-82-83-82zm-85 204c-13 0-24 10-24 23v48c0 13 11 23 24 23h23v119h-23c-13 0-24 11-24 24l-0 47c0 13 11 24 24 24h168c13 0 24-11 24-24l0-47c0-13-11-24-24-24h-21v-190c0-13-11-23-24-23h-123z"></path>
</svg>

<svg height="0" width="0">
  <defs>
    <linearGradient id="lgrad-p" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#4169e1"></stop><stop offset="99%" stop-color="#c44764"></stop></linearGradient>
    <linearGradient id="lgrad-s" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#ef3c3a"></stop><stop offset="99%" stop-color="#6d5eb7"></stop></linearGradient>
    <linearGradient id="lgrad-g" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#585f74"></stop><stop offset="99%" stop-color="#b6bbc8"></stop></linearGradient>
  </defs>
</svg>

<div></div>

<style>
  :first-child {
    height:150px;
    width:150px;
    fill:url(#lgrad-p) blue;
  }
  div{
    position:relative;
    width:150px;
    height:150px;
    fill:url(#lgrad-s) red;
  }
</style>
<script>
  const shadow = document.querySelector('div').attachShadow({mode: 'open'});
  shadow.innerHTML="<svg viewbox=\"0 0 512 512\">\
    <path d=\"m258 0c-45 0-83 38-83 83 0 45 37 83 83 83 45 0 83-39 83-84 0-45-38-82-83-82zm-85 204c-13 0-24 10-24 23v48c0 13 11 23 24 23h23v119h-23c-13 0-24 11-24 24l-0 47c0 13 11 24 24 24h168c13 0 24-11 24-24l0-47c0-13-11-24-24-24h-21v-190c0-13-11-23-24-23h-123z\"></path>\
  </svg>\
  <svg height=\"0\">\
  <defs>\
    <linearGradient id=\"lgrad-s\" gradientTransform=\"rotate(75)\"><stop offset=\"45%\" stop-color=\"#ef3c3a\"></stop><stop offset=\"99%\" stop-color=\"#6d5eb7\"></stop></linearGradient>\
    <linearGradient id=\"lgrad-g\" gradientTransform=\"rotate(75)\"><stop offset=\"45%\" stop-color=\"#585f74\"></stop><stop offset=\"99%\" stop-color=\"#b6bbc8\"></stop></linearGradient>\
  </defs>\
</svg>\
";
</script>

veja meu teste no codepen

O primeiro é SVG normal, o segundo está dentro de um shadow dom.

Roland Gautier
fonte
-4

Aqui está como definir um linearGradient em um elemento de destino:

<style type="text/css">
    path{fill:url('#MyGradient')}
</style>
<defs>
    <linearGradient id="MyGradient">
        <stop offset="0%" stop-color="#e4e4e3" ></stop>
        <stop offset="80%" stop-color="#fff" ></stop>
    </linearGradient>
</defs>
axelparatre
fonte
Nada em questão implica o uso de php.
ACJ