Dégradé SVG en utilisant CSS

102

J'essaie d'obtenir un dégradé appliqué à un rectélément SVG .

Actuellement, j'utilise l' fillattribut. Dans mon fichier CSS:

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

Et l' rectélément a la bonne couleur de remplissage lorsqu'il est affiché dans le navigateur.

Cependant, j'aimerais savoir si je peux appliquer un dégradé linéaire à cet élément?

Hrishikesh Choudhari
la source

Réponses:

95

Utilisez simplement dans le CSS tout ce que vous utiliseriez dans un fillattribut. Bien sûr, cela nécessite que vous ayez défini le dégradé linéaire quelque part dans votre SVG.

Voici un exemple complet:

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
la source
2
Donc , j'ai créé gradient dans un fichier séparé, et utilisé de fillcette façon: fill: url(../js/gradient.svg#MyGradient);. Est-ce la bonne manière?
Hrishikesh Choudhari
@HrishikeshChoudhari: Oui, c'est correct, mais Chrome et je pense que Safari ne prend pas en charge les éléments de référencement d'autres fichiers. Je ne sais pas à propos d'IE9 (impossible de tester pour le moment, essayez-le).
Thomas W
53
À quiconque lit ceci et demande "qu'en est-il fill: linear-gradient (...)?" fillnécessite un <paint>qui est construit autour de la <color>classe CSS2 . En d'autres termes, cette réponse est actuellement le seul moyen de le faire via CSS au moment où j'écris ce commentaire. Vous devez ajouter un linearGradientélément. Enfin, en parcourant le brouillon de travail w3 pour SVG2 , il semble que la prise en charge de linear-gradientla règle de remplissage css ne l'a pas été et pourrait ne pas être intégrée à la spécification.
Arthur Weborg
Comment changer de direction dans ce cas?
AGamePlayer
1
@AwQiruiGuo Jetez un œil à MDN (en particulier l' gradientTransformattribut)
Thomas W
34

Réponse 2019

Avec les toutes nouvelles propriétés css, vous pouvez avoir encore plus de flexibilité avec les variables aka 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>

Définissez simplement une variable nommée pour chacun stopen dégradé, puis personnalisez-la comme vous le souhaitez en css. Vous pouvez même modifier leurs valeurs dynamiquement avec javascript, comme:

document.querySelector('#header-shape-gradient').style.setProperty('--color-stop', "#f5f7f9");
Maciej Kwas
la source
3
Non pris en charge dans IE.
aoakeson le
3
Les propriétés personnalisées CSS sont là depuis très longtemps, si quelqu'un n'est pas encore prêt à les utiliser, il ne sera jamais prêt pour les modifications.
Maciej Kwas
1
@MaciejKwas, vous vous trompez. Les anciens navigateurs ne restent pas éternellement, les entreprises qui ne sont pas prêtes maintenant le seront donc. Et si quelqu'un n'est pas prêt à abandonner une partie de son public, cela ne signifie pas qu'il n'est pas prêt pour les changements, cela signifie qu'il préfère tirer parti des changements plus tard pour garder un public plus large.
Finesse
19
@aoakeson IE est mort. Fin de vie. Edge est également en train de mourir, c'est une réponse de 2019, donc IE ne devrait pas compter. IE peut se dégrader gracieusement en utilisant une couleur unie.
Ciprian
5
@aoakeson Je suis incroyablement surpris de rencontrer ce genre de réponse en 2019. Vous seriez naïf en tant que développeur de supposer que le support SVG dans IE à ce niveau serait un jour pris en charge, sans parler d'un développeur en herbe sur SO vous donnant un , réponse polyfilled pour quelque chose qui est inutilement nécessaire si vous avez l'intention de soutenir IE.
James Martin-Davies le
18

En s'appuyant sur ce que Finesse a écrit, voici un moyen plus simple de cibler le svg et de modifier son dégradé.

Voici ce que vous devez faire:

  1. Attribuez des classes à chaque étape de couleur définie dans l'élément de dégradé.
  2. Ciblez le css et changez la couleur d'arrêt pour chacun de ces arrêts en utilisant des classes simples.
  3. Gagner!

Certains avantages d'utiliser des cours au lieu de :nth-childsont que cela ne sera pas affecté si vous réorganisez vos arrêts. En outre, cela clarifie l'intention de chaque classe - vous vous demanderez si vous aviez besoin d'une couleur bleue sur le premier enfant ou le second.

Je l'ai testé sur tous les Chrome, Firefox et 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>

Voir un exemple modifiable ici: https://jsbin.com/gabuvisuhe/edit?html,css,output

Kumarharsh
la source
Le manque est que vous ne savez pas avec certitude quels sont les noms de classe d'arrêt et quel ordre ils ont. En fait, les solutions sont les mêmes bonnes, la seule différence réside dans les sélecteurs CSS.
Finesse
3
Je pense que c'est la meilleure réponse moderne à la question des PO.
Elemental
9

Voici une solution où vous pouvez ajouter un dégradé et changer ses couleurs en utilisant uniquement 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>

Délicatesse
la source
2

Merci à tous, pour toutes vos réponses précises.

En utilisant le svg dans un shadow dom, j'ajoute les 3 dégradés linéaires dont j'ai besoin dans le svg, à l'intérieur d'un. Je place la règle de remplissage css sur le composant Web et l'héritage od fill fait le travail.

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

voir mon test dans codepen

Le premier est SVG normal, le second est à l'intérieur d'un shadow dom.

Roland Gautier
la source
-4

Voici comment définir un linearGradient sur un élément cible:

<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
la source
Rien dans la question n'implique l'utilisation de php.
ACJ