SVG Тени (Drop Shadows)
Узнайте о тенях, элементах <defs> и <filter>. Примеры SVG-элементов <feOffset>, <feGaussianBlur>, <feColorMatrix>.
Падающая тень (drop shadow) создаёт иллюзию, что SVG-фигура парит над страницей: за ней рисуется размытая смещённая копия. В SVG этот эффект создаётся из низкоуровневых примитивов фильтра — небольших строительных блоков, таких как размытие и смещение, которые объединяются внутри элемента <filter>.
Когда использовать SVG-фильтры, а когда CSS
Существуют три способа добавить тень, и они не взаимозаменяемы:
box-shadow(CSS) — работает с прямоугольной рамкой HTML/CSS-элемента. Он не следует форме SVG-путей, поэтому треугольник всё равно получит прямоугольную тень. Лучше всего подходит для блоков, карточек и кнопок.filter: drop-shadow()(CSS) — следует реальной форме нарисованного объекта (включая SVG-пути и прозрачные PNG). Это самый быстрый способ добавить тень к SVG через таблицу стилей, и он широко поддерживается. Используйте его, когда нужна простая тень без тонкой настройки.- SVG
<filter>(эта глава) — наиболее мощный вариант. Вы управляете каждым шагом (расстояние смещения, радиус размытия, цвет тени, режим наложения) и можете комбинировать несколько примитивов. Используйте его, когда нужна цветная тень, внутренняя тень или любой эффект за пределами обычного размытия.
В этой главе рассматривается подход с SVG <filter>. Другие эффекты фильтров описаны в SVG Blur Effects и введении в SVG-фильтры.
Описание SVG-фильтров
Все SVG-фильтры определяются внутри элемента <defs>. Элемент <defs> — сокращение от definitions (определения). Он содержит определения конкретных элементов, например фильтров. Элемент <filter> задаёт SVG-фильтр. Этот элемент имеет атрибут id (обязательный), идентифицирующий фильтр, на который затем ссылается фигура с помощью filter="url(#id)".
Примитивы фильтра и входные данные
Каждый примитив читает входное изображение и записывает выходное. Два специальных входных значения встроены:
SourceGraphic— исходная фигура со всеми цветами.SourceAlpha— та же фигура, но только с каналом альфа (прозрачности), поэтому результат — сплошной чёрный силуэт. Это обычная отправная точка для тени, поскольку тень должна быть тёмной копией формы, а не перекрашенной копией.
Примитивы соединяются с помощью двух атрибутов:
in— какое изображение читает данный примитив (например,SourceAlphaили имяresultпредыдущего примитива).result— имя, которое вы присваиваете выходным данным этого примитива, чтобы следующий примитив мог их прочитать.
Примитивы, используемые в этой главе:
<feOffset>— сдвигает изображение наdx(по горизонтали) иdy(по вертикали). Это позиционирует тень относительно фигуры.<feGaussianBlur>— размывает изображение. АтрибутstdDeviationзадаёт радиус размытия: чем больше значение, тем мягче и шире тень.<feColorMatrix>— преобразует значения RGBA каждого пикселя, что позволяет окрасить тень в произвольный цвет.<feBlend>/<feMerge>— объединяют два изображения.<feBlend>накладывает два входных изображения (inиin2) с заданнымmode, напримерnormal;<feMerge>слоями укладывает произвольное количество входных данных по порядку. Оба используются здесь, чтобы нарисовать исходную графику поверх готовой тени.
Для создания падающих теней используется элемент <feOffset>. Вы берёте копию SVG-графики, перемещаете её в плоскости XY, затем размываете, а поверх рисуете оригинал.
Пример элемента SVG <feOffset>:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<svg width="150" height="150">
<defs>
<filter id="filter" x="0" y="0" width="150%" height="150%">
<feOffset result="offOut" in="SourceGraphic" dx="30" dy="30" />
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
</filter>
</defs>
<rect width="110" height="110" stroke="purple" stroke-width="5" fill="pink"
filter="url(#filter)" />
Sorry, your browser doesn't support inline SVG.
</svg>
</body>
</html>В приведённом примере атрибут id элемента <filter> задаёт уникальное имя фильтра, а атрибут filter элемента <rect> связывает прямоугольник с этим фильтром. <feOffset> копирует SourceGraphic и сдвигает его на 30px вправо и 30px вниз (dx="30" dy="30"), сохраняя результат как offOut. Затем <feBlend> рисует исходный SourceGraphic поверх offOut, и вы видите фигуру с жёстко смещённой копией позади неё.
Пример элемента SVG <feGaussianBlur>:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<svg width="200" height="200">
<defs>
<filter id="filter" x="0" y="0" width="250%" height="250%">
<feOffset result="offOut" in="SourceGraphic" dx="30" dy="30" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<rect width="150" height="150" stroke="coral" stroke-width="5" fill="pink"
filter="url(#filter)" />
Sorry, your browser doesn't support inline SVG.
</svg>
</body>
</html>Здесь смещённая копия размывается с помощью элемента <feGaussianBlur>. Его атрибут stdDeviation задаёт степень размытия — увеличьте его для более мягкой тени, уменьшите для более чёткой. Поскольку вход по-прежнему SourceGraphic, размытая копия сохраняет цвета фигуры, что обычно не соответствует тому, как выглядит настоящая тень. Следующий пример исправляет это.
Пример чёрной (силуэтной) тени с SourceAlpha:
Чтобы тень была тёмным силуэтом, а не размытым клоном цветной фигуры, передайте в <feOffset> входное значение SourceAlpha вместо SourceGraphic. SourceAlpha содержит только данные прозрачности, поэтому смещённая и размытая копия получается сплошной чёрной — именно такой и должна быть тень.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<svg height="200" width="200">
<defs>
<filter id="filter" x="0" y="0" width="150%" height="150%">
<feOffset result="offOut" in="SourceAlpha" dx="15" dy="15" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="8" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<rect width="120" height="120" stroke="purple" stroke-width="5" fill="pink"
filter="url(#filter)" />
Sorry, your browser doesn't support inline SVG.
</svg>
</body>
</html>Чтобы придать тени произвольный цвет, используйте элемент <feColorMatrix>. Он умножает значения красного, зелёного, синего и альфа-канала каждого пикселя на указанные числа, что позволяет затемнить или перекрасить смещённую копию до её размытия.
Пример окраски тени с помощью <feColorMatrix>:
В матрице ниже каналы красного, зелёного и синего масштабированы до 0.2 (первые три диагональных значения), что затемняет смещённую копию до тусклого цвета, а альфа-канал остаётся 1 (четвёртое диагональное значение), так что тень сохраняет прозрачность фигуры. Измените три значения 0.2, чтобы задать оттенок тени — например, более высокое значение красного даст красноватую тень.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<svg height="200" width="200">
<defs>
<filter id="filter" x="0" y="0" width="150%" height="150%">
<feOffset result="offOut" in="SourceGraphic" dx="25" dy="25" />
<feColorMatrix result="matrixOut" in="offOut" type="matrix"
values="0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0" />
<feGaussianBlur result="blurOut" in="matrixOut" stdDeviation="9" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<rect width="150" height="150" stroke="purple" stroke-width="5" fill="lightblue"
filter="url(#filter)" />
Sorry, your browser doesn't support inline SVG.
</svg>
</body>
</html>Сокращённый примитив <feDropShadow>
Объединять <feOffset>, <feGaussianBlur> и <feBlend> для такого распространённого эффекта довольно многословно. Примитив <feDropShadow> объединяет все три в один элемент и поддерживается во всех современных браузерах. Смещение задаётся через dx / dy, мягкость — через stdDeviation, а цвет — через flood-color (и опционально flood-opacity).
Пример элемента SVG <feDropShadow>:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<svg height="200" width="200">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="150%" height="150%">
<feDropShadow dx="15" dy="15" stdDeviation="8" flood-color="purple" flood-opacity="0.5" />
</filter>
</defs>
<rect width="120" height="120" stroke="purple" stroke-width="5" fill="pink"
filter="url(#shadow)" />
Sorry, your browser doesn't support inline SVG.
</svg>
</body>
</html>Это даёт тот же результат, что и многопримитивные примеры выше, но в одну строку.
Связанные главы SVG
- SVG Blur Effects — использование
<feGaussianBlur>отдельно. - SVG Filters Intro — обзор элемента
<filter>и примитивов. - SVG Introduction — начало работы с SVG в HTML.
- SVG Reference — полный список SVG-элементов и атрибутов.