W3docs

Sombras en SVG

Aprende sobre las sombras en SVG, los elementos <defs> y <filter>. Ve ejemplos de <feOffset>, <feGaussianBlur> y <feColorMatrix>.

Una sombra hace que una figura SVG parezca flotar sobre la página al pintar una copia borrosa y desplazada de la figura detrás de ella. En SVG este efecto se construye a partir de primitivas de filtro de bajo nivel — pequeños bloques de construcción como desenfoque y desplazamiento que se encadenan dentro de un elemento <filter>.

Cuándo usar filtros SVG frente a CSS

Tienes tres maneras de añadir una sombra, y no son intercambiables:

  • box-shadow (CSS) — actúa sobre el rectángulo del elemento HTML/CSS. No sigue la forma de las rutas SVG, por lo que un triángulo sigue teniendo una sombra rectangular. Es la mejor opción para cajas, tarjetas y botones.
  • filter: drop-shadow() (CSS) — sigue la forma real pintada (incluidas rutas SVG y PNG transparentes). Es la forma más rápida de añadir sombra a un SVG desde una hoja de estilos y cuenta con amplia compatibilidad. Úsalo cuando solo necesites una sombra sin control fino.
  • SVG <filter> (este capítulo) — la opción más potente. Controlas cada paso (distancia de desplazamiento, radio de desenfoque, color de la sombra, modo de fusión) y puedes combinar varias primitivas. Úsalo cuando necesites una sombra de color, una sombra interior o cualquier efecto más allá de un simple desenfoque.

Este capítulo cubre el enfoque con <filter> de SVG. Para otros efectos de filtro, consulta Efectos de desenfoque en SVG y la introducción a los filtros SVG.

Descripción de los filtros SVG

Todos los filtros SVG se definen dentro de un elemento <defs>. El elemento <defs> es la forma abreviada de definitions (definiciones). Contiene la definición de elementos específicos como los filtros. El elemento <filter> define un filtro SVG. Este elemento tiene un atributo id (obligatorio) que identifica el filtro, al que luego se hace referencia desde una figura con filter="url(#id)".

Primitivas de filtro y entradas

Cada primitiva lee una imagen de entrada y escribe una imagen de salida. Hay dos entradas especiales integradas:

  • SourceGraphic — la figura original con todos sus colores.
  • SourceAlpha — la misma figura pero usando únicamente su canal alfa (opacidad), por lo que aparece como una silueta negra sólida. Este es el punto de partida habitual para una sombra, ya que una sombra debe ser una copia oscura de la figura, no una copia recoloreada.

Las primitivas se conectan entre sí mediante dos atributos:

  • in — qué imagen lee esta primitiva (p. ej. SourceAlpha, o el nombre de result de una primitiva anterior).
  • result — nombre que se asigna a la salida de esta primitiva para que una primitiva posterior pueda leerla.

Las primitivas utilizadas en este capítulo:

  • <feOffset> — desplaza una imagen en dx (horizontal) y dy (vertical). Esto posiciona la sombra alejada de la figura.
  • <feGaussianBlur> — desenfoca una imagen. Su atributo stdDeviation establece el radio de desenfoque: valores mayores dan una sombra más suave y amplia.
  • <feColorMatrix> — transforma los valores RGBA de cada píxel, lo que permite teñir la sombra con un color personalizado.
  • <feBlend> / <feMerge> — combinan dos imágenes. <feBlend> apila dos entradas (in e in2) usando un mode como normal; <feMerge> superpone cualquier número de entradas en orden. Ambas se utilizan aquí para pintar el gráfico original encima de la sombra terminada.

Para crear sombras, se usa el elemento <feOffset>. Se toma una copia del gráfico SVG, se mueve en el plano XY, se desenfoca y luego se dibuja el original encima.

Ejemplo del elemento 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>

En el ejemplo anterior, el atributo id del elemento <filter> especifica un nombre único para el filtro, y el atributo filter del elemento <rect> vincula el rectángulo con ese filtro. <feOffset> copia SourceGraphic y lo mueve 30 px hacia la derecha y 30 px hacia abajo (dx="30" dy="30"), guardando el resultado como offOut. Luego <feBlend> dibuja el SourceGraphic original encima de offOut, de modo que se ve la figura con una copia desplazada de bordes definidos detrás.

Ejemplo del elemento 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>

Aquí la copia desplazada se desenfoca con el elemento <feGaussianBlur>. Su atributo stdDeviation especifica la cantidad de desenfoque — auméntalo para una sombra más suave, redúcelo para una más nítida. Como la entrada sigue siendo SourceGraphic, la copia desenfocada conserva los colores de la figura, lo que normalmente no se corresponde con el aspecto de una sombra real. El siguiente ejemplo soluciona eso.

Ejemplo de sombra negra (silueta) con SourceAlpha:

Para convertir la sombra en una silueta oscura en lugar de un clon borroso de la figura coloreada, se alimenta <feOffset> con la entrada SourceAlpha en lugar de SourceGraphic. SourceAlpha solo transporta opacidad, por lo que la copia desplazada y desenfocada sale en negro sólido — exactamente lo que debe ser una sombra.

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

Para teñir la sombra con un color personalizado, se usa el elemento <feColorMatrix>. Multiplica los valores rojo, verde, azul y alfa de cada píxel por los números que se proporcionan, lo que permite oscurecer o recolorear la copia desplazada antes de desenfocarla.

Ejemplo de colorear la sombra con <feColorMatrix>:

En la matriz siguiente, los canales rojo, verde y azul se escalan cada uno a 0.2 (los primeros tres valores de la diagonal), lo que oscurece la copia desplazada hacia un color tenue, mientras que el canal alfa permanece en 1 (el cuarto valor diagonal) para que la sombra conserve la opacidad de la figura. Cambia los tres valores 0.2 para teñir la sombra — por ejemplo, un valor rojo mayor da una sombra rojiza.

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

El atajo <feDropShadow>

Encadenar <feOffset>, <feGaussianBlur> y <feBlend> resulta verboso para un efecto tan común. La primitiva <feDropShadow> agrupa los tres en un solo elemento y es compatible con los navegadores modernos. El desplazamiento se establece con dx / dy, la suavidad con stdDeviation y el color con flood-color (y opcionalmente flood-opacity).

Ejemplo del elemento 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>

Esto produce el mismo tipo de resultado que los ejemplos con múltiples primitivas, pero con una sola línea.

Capítulos SVG relacionados

Práctica

Práctica
¿Qué entrada de filtro SVG debes usar en 'feOffset' para crear una sombra de silueta negra en lugar de una copia recoloreada de la figura?
¿Qué entrada de filtro SVG debes usar en 'feOffset' para crear una sombra de silueta negra en lugar de una copia recoloreada de la figura?
Was this page helpful?