Gradiente SVG usando CSS

102

Estoy tratando de aplicar un degradado a un rectelemento SVG .

Actualmente, estoy usando el fillatributo. En mi archivo CSS:

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

Y el rectelemento tiene el color de relleno correcto cuando se ve en el navegador.

Sin embargo, me gustaría saber si puedo aplicar un degradado lineal a este elemento.

Hrishikesh Choudhari
fuente

Respuestas:

95

Simplemente use en el CSS lo que usaría en un fillatributo. Por supuesto, esto requiere que haya definido el gradiente lineal en algún lugar de su SVG.

Aquí tienes un ejemplo 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
fuente
2
Así que creé ese gradiente en un archivo separado, y se utiliza fillde esta manera: fill: url(../js/gradient.svg#MyGradient);. ¿Es este el camino correcto?
Hrishikesh Choudhari
@HrishikeshChoudhari: Sí, esto es correcto, pero Chrome y yo creo que Safari tampoco admite la referencia a elementos de otros archivos. No estoy seguro acerca de IE9 (no puedo probarlo en este momento, solo pruébalo).
Thomas W
53
A cualquiera que lea esto y pregunte "¿sobre qué fill: linear-gradient (...)?" fillrequiere un <paint>que se basa en la <color>clase CSS2 . En otras palabras, esta respuesta es actualmente la única forma de hacerlo a través de CSS en el momento en que escribo este comentario. Necesitas agregar un linearGradientelemento. Por último, al revisar el Borrador de trabajo de w3 para SVG2 , parece que el soporte para linear-gradientla regla de relleno css no lo ha hecho y podría no estar incluido en la especificación.
Arthur Weborg
¿Cómo cambiar la dirección en este caso?
AGamePlayer
1
@AwQiruiGuo Eche un vistazo a MDN (específicamente el gradientTransformatributo)
Thomas W
34

Respuesta 2019

Con las nuevas propiedades CSS, puede tener aún más flexibilidad con las variables, también conocidas 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>

Simplemente configure una variable con nombre para cada uno stopen degradado y luego personalícelo como desee en css. Incluso puede cambiar sus valores dinámicamente con javascript, como:

document.querySelector('#header-shape-gradient').style.setProperty('--color-stop', "#f5f7f9");
Maciej Kwas
fuente
3
No es compatible con IE.
aoakeson
3
Las propiedades personalizadas de CSS están aquí durante mucho tiempo, si de alguna manera alguien aún no está listo para usarlas, nunca estará listo para los cambios.
Maciej Kwas
1
@MaciejKwas, estás equivocado. Los navegadores antiguos no se quedan para siempre, por lo que las empresas que no están listas ahora lo estarán entonces. Y si alguien no está listo para descartar una parte de su audiencia, no significa que no esté listo para los cambios, significa que prefiere aprovechar los cambios más adelante para mantener una audiencia más grande.
Finesse
19
@aoakeson IE está muerto. Fin de vida. Edge también está muriendo, esta es una respuesta de 2019, por lo que IE no debería contar. IE se puede degradar con gracia usando un color sólido.
Ciprian
5
@aoakeson Estoy increíblemente sorprendido de encontrarme con ese tipo de respuesta en 2019. Sería ingenuo como desarrollador si asumiera que el soporte SVG en IE en este nivel alguna vez sería compatible, y mucho menos un desarrollador en ciernes en SO dándole un inflado , respuesta con relleno múltiple para algo innecesariamente necesario si tiene la intención de admitir IE.
James Martin-Davies
18

Sobre la base de lo que escribió Finesse, aquí hay una forma más sencilla de apuntar al svg y cambiar su gradiente.

Esto es lo que necesitas hacer:

  1. Asigne clases a cada parada de color definida en el elemento de degradado.
  2. Apunte al css y cambie el color de parada para cada una de esas paradas usando clases simples.
  3. ¡Ganar!

Algunos de los beneficios de usar clases en lugar de :nth-childes que no se verá afectado si reordena sus paradas. Además, deja en claro la intención de cada clase: se quedará preguntándose si necesitaba un color azul en el primer niño o en el segundo.

Lo he probado en todos los 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>

Vea un ejemplo editable aquí: https://jsbin.com/gabuvisuhe/edit?html,css,output

Kumarharsh
fuente
La falta es que no sabe con certeza cuáles son los nombres de las clases de parada y qué orden tienen. En realidad, las soluciones son las mismas buenas, la única diferencia son los selectores de CSS.
Finesse
3
Creo que esta es la mejor respuesta moderna a la pregunta de los PO.
Elemental
9

Aquí hay una solución en la que puede agregar un degradado y cambiar sus colores usando solo 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>

Finura
fuente
2

Gracias a todos por todas sus respuestas precisas.

Usando el svg en un dom de sombra, agrego los 3 gradientes lineales que necesito dentro del svg, dentro de a. Coloco la regla de relleno css en el componente web y la herencia de relleno hace el trabajo.

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

ver mi prueba en codepen

El primero es SVG normal, el segundo está dentro de un dom de sombra.

Roland Gautier
fuente
-4

A continuación se explica cómo establecer un linearGradient en un 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
fuente
Nada en la pregunta implica el uso de php.
ACJ