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?

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>


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");

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


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>


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.


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

Nic w pytaniu nie sugeruje użycia php.
— ACJ
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.