adgllorente

Imágenes SVG responsive en ReactJS

An iPad showing the process of designing an icon. The iPad is over a paper with many icons already designed.

Photo by Balázs Kétyi on Unsplash · 25/8/2021

Cuando trabajamos con imágenes de tipo SVG vemos que en algunos casos no tienen por qué comportarse como las imágenes rasterizadas como JPEG, GIF, PNG, etc.

A diferencia de las imágenes rasterizadas que tienen un aspect ratio implícito definido por la matriz de píxeles que conforman la imagen, los SVGs pueden no tener definido un aspect ratio específico. En este caso podríamos decir que los documentos de tipo SVG tienen un comportamiento similar al de un <iframe> y no tienen por qué ajustarse al tamaño del contenedor.

El escalado en los SVGs

Un SVG no se comporta como el resto de imágenes, sin embargo, la especificación define una serie de propiedades que pueden configurarse para definir un aspect ratio y facilitar el renderizado en el browser.

Propiedades width y height

La especificación de SVG indica que pueden añadirse 2 atributos width y height al SVG.

<svg version="1.1" width="120" height="120">

Sin profundizar, estas propiedades definen el tamaño del documento SVG pero no garantizan que la imagen se vaya a ajustar a esos tamaños en todos los browsers.

Propiedad viewBox

Para garantizar que un SVG se escale como esperamos, tenemos que definir la propiedad viewBox.

Esta propiedad se especifica como un atributo del tag SVG y define varias cosas:

  • El aspect ratio del SVG
  • Como se escalan todas las dimensiones que conforman la imagen
  • El punto de origen desde el que se comenzará a pintar el SVG.
<svg version="1.1" viewBox="0 0 32 32">

La propiedad viewBox es la que hará que nuestro SVG se escale de una manera similar a como lo hace una imagen rasterizada

Usando SVGs en ReactJS

A la hora de trabajar con SVGs en ReactJS tenemos varias opciones con sus pros y sus contras.

Renderizar el SVG dentro de un tag img

Una de las opciones, quizá la mas directa, es importar los SVG dentro de un tag <img>.

Usando el tag <img> conseguiremos:

  • Reducir el tamaño de nuestro HTML, si el SVG es muy grande puede ser un impacto en la performance.
  • Optimizar la carga de la imagen aprovechando propiedades como loading=“lazy” para que no se cargue el SVG hasta que entre dentro del viewport.

Sin embargo, al importar un SVG de esta manera también tenemos un contra:

  • No se podrá modificar el color del SVG usando fill. Sin embargo, podemos usar los filtros CSS para cambiar algún color.

Renderizar el SVG Inline en un tag svg

Si importamos el SVG inline, es decir, usando un tag <svg> tendremos acceso a sus propiedades de color, lo que nos permitirá:

  • Personalizar los colores con CSS usando la propiedad fill y color.

Por contra:

  • Nuestro HTML aumentará de tamaño y puede suponer un problema de performance.
  • No podremos cargar el SVG cuando esté dentro del viewport.

Importar un SVG en ReactJS con Webpack

Ya hemos visto que los SVG se pueden importar de dos maneras diferentes: Inline y en un <img>. Ambas con sus pros y sus contras.

A continuación vamos a ver cómo podemos configurar nuestro proyecto de ReactJS con Webpack para importar los SVG.

Configurar el plugin @svgr/webpack.

El plugin @svgr/webpack nos va facilitar importar los SVGs de las dos maneras que hemos visto anteriormente, inline y como una URL para usar en un tag <img>.

Lo primero de todo es instalar las dependencias, verás que hemos añadido file-loader, es probable que ya lo tengas en tu proyecto, pero por si acaso.

npm i -D @svgr/webpack file-loader

A continuación vamos a añadir un loader a Webpack para que se encargue de los ficheros .svg. Abrimos el fichero de configuración de Webpack y añadimos lo siguiente:

{
  test: /\.svg$/,
  use: [
    // Inserts the SVG inline.
    '@svgr/webpack',
    // Generates a URL to insert the SVG as an image.
    {
      loader: 'file-loader',
      // Defines an output hash for cache.
      options: {
        outputPath: './assets/',
        name: '[name]-[hash].[ext]'
      }
    }
  ]
}

Importar una imagen SVG en nuestro componente.

Tras haber configurado Webpack, ya podremos importar una imagen SVG dentro de nuestros componentes de ReactJS.

A continuación vamos a importar el SVG de las dos maneras que hemos comentado.

// default import (svgImage) is going to be a URL.
// ReactComponent is a ReactJS component to be used inline.
import svgImage, { ReactComponent as MySVGComponent } from "demo-image.svg";

Ahora ya podremos usar nuestro SVG de la forma que más se ajuste a nuestras necesidades.

function demoComponent() {
  return (
    <>
      {/** SVG inserted as an inline */}
      <img
        src={svgImage}
        alt="Add a descriptive alternative text, this is usefull for blind people"
      />

      {/** SVG inserted inline as a ReactComponent. */}
      <ReactComponent style=\{\{ color: black \}\} />
    </>
  );
}

Conclusión

Cualquiera de las dos opciones de importación es válida a la hora de inyectar un SVG en nuestra aplicación ReactJS. Dependerá de cuáles sean nuestras necesidades.

Si queremos modificar el SVG usando CSS es mejor que lo importemos inline, por ejemplo para iconos.

Si se trata de una imagen tipo ilustración cuyos colores no se van a modificar, puedes importarlo dentro del tag <img>

Usando el plugin @svgr/webpack puedes cambiar fácilmente de una opción a otra.

Linkografía

reactjs svg webpack

· Adrián Gómez

Powered by Astro + TailwindCSS + Markdown

Inspired in London and Julia