SVG-градиенты

Содержание:
Управление цветами
Линейный градиент
Радиальный градиент
gradientUnits
gradientTransform
spreadMethod
xlink:href
Подводные камни
Примеры использования

В SVG не работают привычные CSS-фоны, для заливок здесь есть свои конструкции: для градиентов это элементы linearGradient и radialGradient — линейный и радиальный градиенты соответственно.

Спецификация: w3.org/TR/SVG/pservers.html#Gradients

CSS-градиенты объявляются прямо в CSS-коде, и код самого градиента потом нельзя переиспользовать. SVG-градиенты устроены иначе: перед использованием градиент должен быть описан с помощью соответствующего тега, и после этого его можно переиспользовать сколько угодно раз. И даже больше: градиенты могут наследовать свойства друг друга (об этом будет рассказано ниже).

Код самого простого градиента выглядит вот так:

<linearGradient id="linear-gradient">
    <stop offset="0%" stop-color="gold"/>
    <stop offset="100%" stop-color="teal"/>
</linearGradient>

Обязательный атрибут любого градиента — id.

Градиент не отображается на странице, пока не будет применён к элементу. Так же, как и обычная заливка или обводка, градиент задаётся с помощью fill или stroke — атрибутом элемента или через CSS.

Применим градиент к фигуре:

<svg>
  <!-- Градиент -->
  <linearGradient id="linear-gradient">
    <stop offset="0%" stop-color="gold"/>
    <stop offset="100%" stop-color="teal"/>
  </linearGradient>

  <!-- Фигура с градиентной заливкой -->
  <rect fill="url(#linear-gradient)"
        width="100%" height="100%"/>
</svg>

В действии:

Градиент можно использовать и как заливку и как обводку для фигур и для текста:

See the Pen NAZgqo by yoksel (@yoksel) on CodePen.

Управление цветами

Для управлениям цветами градиента служит элемент stop. Атрибуты:

  • offset — положение цвета
  • stop-color — цвет
  • stop-opacity — прозрачность цвета

Пример кода:

<stop offset=".25" stop-color="blue" stop-opacity=".5"/>

Положение цвета задаётся в процентах или числом от 0 до 1 (50% и .5 будут работать одинаково). Цвет и положение цвета указывать обязательно.

Интересно, что в отличие от CSS-градиентов, цвета SVG-градиентов можно анимировать (в данном случае, с помощью CSS):

See the Pen Animated SVG-gradient by yoksel (@yoksel) on CodePen.

Линейный и радиальный градиенты имеют несколько общих свойств, но различаются способами, которыми задаются размер и направление градиента. Рассмотрим их поподробнее.

Линейный градиент

Задаётся с помощью тэга linearGradient.

Вектор градиента задаётся с помощью атрибутов x1, y1, x2 и y2.

x1 и y1 задают координаты начала вектора, x2 и y2 — координаты конца (похоже на рисование линии с помощью тега line).

See the Pen Gradient Coords: x2 & y2 by yoksel (@yoksel) on CodePen.

Если координаты не заданы, рисуется горизонтальный градиент слева направо.

Кнопки вверху демо переключают свойство gradientUnits, отвечающее за систему координат, подробнее о нём будет рассказано ниже.

Радиальный градиент

Задаётся с помощью тега radialGradient.

Параметры градиента задаются с помощью тех же атрибутов, что определяют свойства круга (элемента circle): центр фигуры задаётся атрибутами cx и cy, а радиус — атрибутом r:

See the Pen Gradient Coords: r by yoksel (@yoksel) on CodePen.

Если какой-то из этих атрибутов не задан, ему присвоится значение по умолчанию, равное 50%.

Помимо этого, у радиального градиента есть пара специфических свойств: fx и fy. Они позволяют сдвинуть только центр градиента, не затрагивая расположение конечных цветов:

See the Pen Gradient Coords: fx & fy by yoksel (@yoksel) on CodePen.

Если эти атрибуты не заданы, их значения по умолчанию будут равны cx и cy соответственно.

Общие свойства градиентов

gradientUnits

Это очень важное свойство, оно задаёт систему координат для атрибутов, отвечающих за направление и размеры градиента (x1, y1, x2 и y2 для линейных градиентов и cx, cy, r, fx и fy для радиальных).

Возможные значения:

objectBoundingBox — координаты рассчитываются относительно объекта, к которому применяется градиент. Значение по умолчанию. userSpaceOnUse — координаты рассчитываются относительно системы координат всего SVG-элемента.

Помимо того, что при переключении gradientUnits градиент может менять своё положение из-за смены системы координат, это свойство также может существенно влиять на отрисовку градиента для фигур с разными шириной и высотой (например, вытянутый прямоугольник или эллипс).

При значении userSpaceOnUse цвета линейного градиента всегда будут перпендикулярны основному вектору, а радиальный градиент будет иметь форму круга. Но если градиент задан вытянутой фигуре, а значение gradientUnits равно objectBoundingBox, градиент пытается уместиться в фигуру целиком и подвергается искажениям. Особенно это заметно на радиальных градиентах:

See the Pen gradientUnits (radialGradient) by yoksel (@yoksel) on CodePen.

У линейных градиентов в этом случае меняется угол расположения цветов градиента относительно его вектора:

See the Pen gradientUnits by yoksel (@yoksel) on CodePen.

Так что даже если системы координат фигуры и SVG-элемента совпадают, из-за разных значений gradientUnits градиент может выглядеть по-разному.

gradientTransform

Атрибут позволяет задать трансформациии градиента:

See the Pen gradientTransform by yoksel (@yoksel) on CodePen.

Трансформации те же, что и для обычных фигур, например, градиент можно повернуть или растянуть, но в трансформациях градиентов есть некоторые подводные камни.

Для градиентов, как и для всех прочих элементов, по умолчанию трансформации производятся относительно верхнего левого угла документа. Если требуется переопределить центр трансформации, нужно задать transform-origin. Явно в атрибуте его можно задать только для rotate (например, rotate(180, 100, 100), два последних числа — это оно), для других трансформаций transform-origin будет работать только если он вместе с трансформацией задан в CSS. Но gradientTransform нельзя задать через CSS, следовательно transform-origin так тоже задать не получится. В этом случае можно использовать центрирование через translate (за подсказку спасибо @AmeliasBrain):

translate(x,y) scale(s) translate(-x,-y).

В случае с радиальным градиентом вместо scale будет удобнее управлять радиусом градиента.

spreadMethod

Этот атритбут управляет поведением градиента, если градиент меньше, чем область отрисовки.

Возможные значения:

pad — свободное пространство заполняется крайними цветами. Значение по умолчанию. reflect — градиент отражается. repeat — градиент повторяется.

See the Pen SpreadMethods for SVG Gradients by yoksel (@yoksel) on CodePen.

spreadMethod не работает в Safari. Если надо чтобы везде работало, линейные повторяющиеся и отражённые градиенты можно имитировать с помощью паттернов, а повторение радиальных всё-таки придётся прописывать руками.

Этот атрибут позволяет градиентам заимствовать друг у друга цвета и свойства. Если в градиенте, содержащем атрибут xlink:href, не заданы цвета, они унаследуются из градиента по ссылке. Также из заданного градиента унаследуются все свойства, которые не переопределены в текущем градиенте. При этом радиальные градиенты могут наследовать цвета и свойства линейного, и наоборот.

Вот пример использования:

<!-- Исходный линейный градиент -->
<linearGradient id="linear-gradient">
    <stop offset="0%" stop-color="crimson"
          class="stop-1"/>
    <stop offset="49%" stop-color="gold"
          class="stop-2"/>
    <stop offset="50%" stop-color="lemonchiffon"
          class="stop-2"/>
    <stop offset="51%" stop-color="gold"
          class="stop-2"/>
    <stop offset="100%" stop-color="teal"
          class="stop-3"/>
</linearGradient>

<!-- Радиальный градиент, наследующий цвета и свойства линейного -->
<radialGradient id="radial-gradient"
    xlink:href="#linear-gradient">
</radialGradient>

Код в действии, радиальный градиент справа унаследовал цвета линейного градиента слева:

See the Pen Gradient properties inheritance by yoksel (@yoksel) on CodePen.

В этом демо к градиенту слева применяется трансформация, и она также наследуется градиентом справа.

Подводные камни

Градиент можно использовать в качестве заливки и обводки, и задавать его можно как атрибутами fill и stroke, так и в CSS. При этом можно сложить градиенты в отдельный файл, и подключать их оттуда, это избавит от необходимости вставлять градиенты в тело документа.

К сожалению, все самые удобные и интересные способы не очень хорошо поддерживаются браузерами. Так, в CSS запись вида fill: url(#grad); подразумевает, что градиент с таким ID нужно искать в текущем документе. В Хроме, Опере и Сафари всё так и происходит, однако Firefox начинает искать градиент относительно расположения файла со стилями, и ожидаемо ничего не находит. Можно привести ссылку в CSS в соответствие с адресом страницы, но это не поможет, если страниц больше одной.

Запись вроде fill: url(svg-with-gradients.svg#gradient); указывает, что градиент нужно брать из внешнего файла, и это было бы суперудобно, но, к сожалению, работает только в Firefox.

Таким образом, самый надёжный способ — это задавать градиент используя атрибуты элемента.

Примеры использования

SVG-градиенты сами по себе дают интересные возможности оформления, но ещё интереснее то, как они работают в сочетании с масками. Например, используя маски и градиенты можно сделать вот такие мыльные пузыри:

See the Pen SVG Bubbles by yoksel (@yoksel) on CodePen.

Тут есть подробная схема отдельного пузыря.

Также анимируя градиенты можно делать разные интересные штуки. Например, вот такой паттерн (цвета анимируются с помощью CSS):

See the Pen Animated pattern with SVG gradient by yoksel (@yoksel) on CodePen.

Или переливающийся текст:

See the Pen Text with gradientTransform by yoksel (@yoksel) on CodePen.

Анимацию цветов можно сделать с помощью CSS, трансформации можно добавить только с помощью JavaScript (я это делаю с помощью библиотеки GSAP).

Если вы нашли ошибку или неточность, вы можете отредактировать статью с помощью prose.io, а также можно написать мне в комментариях или в Twitter.
Система комментирования от Disqus