W3docs

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-элементов и атрибутов.

Практика

Практика
Какое входное значение SVG-фильтра нужно передать в 'feOffset', чтобы получить чёрную силуэтную тень, а не перекрашенную копию фигуры?
Какое входное значение SVG-фильтра нужно передать в 'feOffset', чтобы получить чёрную силуэтную тень, а не перекрашенную копию фигуры?
Was this page helpful?