Gradient SVG przy użyciu CSS

104

Próbuję uzyskać gradient zastosowany do rectelementu SVG .

Obecnie używam fillatrybutu. W moim pliku CSS:

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

A rectelement ma prawidłowy kolor wypełnienia podczas przeglądania w przeglądarce.

Chciałbym jednak wiedzieć, czy mogę zastosować gradient liniowy do tego elementu?

Hrishikesh Choudhari
źródło

Odpowiedzi:

96

Po prostu użyj w CSS tego, czego użyłbyś w fillatrybucie. Oczywiście wymaga to zdefiniowania gradientu liniowego gdzieś w pliku SVG.

Oto pełny przykład:

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.
źródło
2
Więc stworzyłem tego gradientu w osobnym pliku, a stosowany fillw ten sposób: fill: url(../js/gradient.svg#MyGradient);. Czy to dobra droga?
Hrishikesh Choudhari
@HrishikeshChoudhari: Tak, to jest poprawne, ale Chrome i myślę, że Safari również nie obsługują odwołań do elementów z innych plików. Nie jestem pewien co do IE9 (nie można teraz przetestować, po prostu spróbuj).
Thomas W.
53
Do każdego, kto to przeczyta i zapyta „o czym fill: linear-gradient (...)?” fillwymaga, <paint>który jest zbudowany wokół <color>klasy CSS2 . Innymi słowy, ta odpowiedź jest obecnie jedynym sposobem na zrobienie tego przez CSS w czasie, gdy piszę ten komentarz. Musisz dodać linearGradientelement. Wreszcie, przechodząc przez wersję roboczą w3 dla SVG2 , wydaje się, że wsparcie dla linear-gradientreguły css wypełnienia nie ma i może nie znaleźć się w specyfikacji.
Arthur Weborg
Jak zmienić kierunek w tym przypadku?
AGamePlayer
1
@AwQiruiGuo Spójrz na MDN (konkretnie gradientTransformatrybut)
Thomas W
34

Odpowiedź 2019

Dzięki zupełnie nowym właściwościom CSS możesz mieć jeszcze większą elastyczność dzięki zmiennym 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>

Po prostu ustaw nazwaną zmienną dla każdej stopw gradiencie, a następnie dostosuj, jak chcesz w css. Możesz nawet dynamicznie zmieniać ich wartości za pomocą javascript, na przykład:

document.querySelector('#header-shape-gradient').style.setProperty('--color-stop', "#f5f7f9");
Maciej Kwas
źródło
3
Nieobsługiwane w IE.
aoakeson
3
Własności CSS są tu od bardzo dawna, jeśli ktoś nie jest jeszcze gotowy na ich użycie, to nigdy nie będzie gotowy na zmiany.
Maciej Kwas
1
@MaciejKwas, mylisz się. Stare przeglądarki nie pozostają na zawsze, więc firmy, które nie są teraz gotowe, będą wtedy gotowe. A jeśli ktoś nie jest gotowy odrzucić części swojej publiczności, nie oznacza to, że nie jest gotowy na zmiany, oznacza to, że woli później wykorzystać zmiany, aby zatrzymać większą publiczność.
Finezja
19
@aoakeson IE nie żyje. Koniec życia. Edge też umiera, to jest odpowiedź 2019, więc IE nie powinno się liczyć. IE może się z wdziękiem degradować, używając jednolitego koloru.
Ciprian,
5
@aoakeson Jestem niesamowicie zaskoczony, gdy natknąłem się na tego rodzaju odpowiedź w 2019 roku. Jako programista byłbyś naiwny, gdybyś założył, że obsługa SVG w IE na tym poziomie będzie kiedykolwiek obsługiwana, nie mówiąc już o początkującym deweloperze SO, który daje ci nadęty , wypełniona odpowiedź na coś, co jest niepotrzebnie potrzebne, jeśli zamierzasz wspierać IE.
James Martin-Davies
18

Opierając się na tym, co napisał Finesse, oto prostszy sposób na celowanie w svg i zmianę jego gradientu.

Oto, co musisz zrobić:

  1. Przypisz klasy do każdego zatrzymania koloru zdefiniowanego w elemencie gradientu.
  2. Skieruj na css i zmień kolor stopu dla każdego z tych przystanków, używając zwykłych klas.
  3. Zdobyć!

Niektóre zalety używania klas zamiast :nth-child są takie, że zmiana kolejności przystanków nie będzie miała na to wpływu. Ponadto jasno określa intencje każdej klasy - będziesz się zastanawiać, czy potrzebujesz niebieskiego koloru na pierwszym czy drugim dziecku.

Przetestowałem to na wszystkich Chrome, Firefox i 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>

Zobacz edytowalny przykład tutaj: https://jsbin.com/gabuvisuhe/edit?html,css,output

kumarharsh
źródło
Brak jest taki, że nie wiesz na pewno, jakie są nazwy klas zatrzymania i jaką mają kolejność. Właściwie rozwiązania są tak samo dobre, jedyną różnicą są selektory CSS.
Finezja
3
Myślę, że to najlepsza współczesna odpowiedź na pytanie dotyczące PO.
Elemental
9

Oto rozwiązanie, w którym możesz dodać gradient i zmienić jego kolory za pomocą tylko 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>

Impas
źródło
2

Dziękuję wszystkim za wszystkie precyzyjne odpowiedzi.

Używając svg w shadow dom, dodaję 3 liniowe gradienty, których potrzebuję w svg, wewnątrz pliku. Umieszczam regułę wypełnienia css w komponencie sieciowym i dziedziczenie wypełnienia wykonuje zadanie.

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

zobacz mój test w codepen

Pierwsza z nich to normalny SVG, druga jest w cieniu.

Roland Gautier
źródło
-4

Oto jak ustawić linearGradient w elemencie docelowym:

<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
źródło
Nic w pytaniu nie sugeruje użycia php.
ACJ