SVG-градиент с использованием CSS

104

Я пытаюсь применить градиент к rectэлементу SVG .

В настоящее время я использую fillатрибут. В моем файле CSS:

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

И rectэлемент имеет правильный цвет заливки при просмотре в браузере.

Однако я хотел бы знать, могу ли я применить к этому элементу линейный градиент?

Хришикеш Чоудхари
источник

Ответы:

96

Просто используйте в CSS все, что вы бы использовали в fill атрибуте. Конечно, для этого необходимо, чтобы вы определили линейный градиент где-то в вашем SVG.

Вот полный пример:

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
Так что я создал этот градиент в отдельном файле, и используется fillследующим образом: fill: url(../js/gradient.svg#MyGradient);. Это правильный путь?
Хришикеш Чоудхари,
@HrishikeshChoudhari: Да, это правильно, но Chrome и я думаю, что Safari также не поддерживает ссылки на элементы из других файлов. Не уверен насчет IE9 (сейчас не могу протестировать, просто попробуйте).
Thomas W
53
Всем, кто читает это и спрашивает "о чем fill: linear-gradient (...)?" fillтребуется, <paint>который построен на основе <color>класса CSS2 . Другими словами, на момент написания этого комментария этот ответ - единственный способ сделать это через CSS. Вам нужно добавить linearGradientэлемент. Наконец, просматривая рабочий проект w3 для SVG2 , выяснилось , что поддержка linear-gradientправила CSS для заполнения отсутствует и может не попасть в спецификацию.
Артур Веборг, 06
Как изменить направление в этом случае?
AGamePlayer
1
@AwQiruiGuo Взгляните на MDN (в частности, gradientTransformатрибут)
Thomas W
34

Ответ 2019

С новыми свойствами css вы можете иметь еще большую гибкость с переменными, также известными как 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>

Просто установите именованную переменную для каждого stopв градиенте, а затем настройте, как вам нравится, в css. Вы даже можете динамически изменять их значения с помощью javascript, например:

document.querySelector('#header-shape-gradient').style.setProperty('--color-stop', "#f5f7f9");
Мацей Квас
источник
3
Не поддерживается в IE.
aoakeson
3
Настраиваемые свойства CSS существуют уже очень давно, и если кто-то еще не готов их использовать, то он никогда не будет готов к изменениям.
Maciej
1
@MaciejKwas, вы ошибаетесь. Старые браузеры не остаются навсегда, поэтому компании, которые не готовы сейчас, будут готовы тогда. И если кто-то не готов отказаться от части своей аудитории, это не означает, что он не готов к изменениям, это означает, что он предпочитает использовать изменения позже, чтобы сохранить большую аудиторию.
Finesse
19
@aoakeson IE мертв. Конец жизни. Edge тоже умирает, это ответ 2019 года, так что IE не стоит рассчитывать. IE может постепенно ухудшаться, используя сплошной цвет.
Ciprian
5
@aoakeson Я удивительно удивлен, встретив такой ответ в 2019 году. Вы, как разработчик, были бы наивны, полагая, что поддержка SVG в IE на этом уровне когда-либо будет поддерживаться, не говоря уже о начинающем разработчике на SO, дающем вам раздутый , полифиллированный ответ на что-то излишне необходимое, если вы собираетесь поддерживать IE.
Джеймс Мартин-Дэвис,
18

Основываясь на том, что написал Finesse, вот более простой способ настроить svg и изменить его градиент.

Вот что вам нужно сделать:

  1. Назначьте классы каждому ограничителю цвета, определенному в элементе градиента.
  2. Нацельтесь на css и измените цвет стопа для каждой из этих остановок, используя простые классы.
  3. Выиграть!

Некоторые преимущества использования классов вместо того :nth-child, что это не повлияет, если вы измените порядок своих стопов. Кроме того, это проясняет цель каждого класса - вам останется только задуматься, нужен ли вам синий цвет для первого дочернего элемента или для второго.

Я тестировал его на всех Chrome, Firefox и 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>

См. Редактируемый пример здесь: https://jsbin.com/gabuvisuhe/edit?html,css,output

кумархарш
источник
Недостаток в том, что вы не знаете наверняка, что такое имена стоп-классов и в каком порядке они расположены. Собственно решения такие же хорошие, разница только в селекторах CSS.
Finesse
3
Я думаю, что это лучший современный ответ на вопрос ОП.
Elemental
9

Вот решение, в котором вы можете добавить градиент и изменить его цвета, используя только 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

Спасибо всем за точные ответы.

Используя svg в теневом домене, я добавляю 3 линейных градиента, которые мне нужны в svg, внутри файла. Я помещаю правило заполнения css в веб-компонент, и наследование od fill выполняет свою работу.

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

см. мой тест в коде

Первый - обычный SVG, второй - внутри теневого дома.

Ролан Готье
источник
-4

Вот как установить linearGradient для целевого элемента:

<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>
аксельпаратр
источник
Ничто в вопросе не подразумевает использование php.
ACJ