Sistema de iconos con Sprites SVG | Programar Plus

He sido un gran defensor de las fuentes de iconos. Muchos sitios realmente necesitan un sistema para iconos, y las fuentes de iconos ofrecen un sistema excelente. Sin embargo, creo asumiendo que eres bueno con IE 9+, usando SVG en línea y el <use> elemento para hacer referencia a un icono es un sistema superior.

Primero veamos cómo funciona.

Una buena forma de manejar sus íconos es tener una carpeta llena de .svg archivos.

Esa es una de las cosas interesantes de trabajar con SVG: son los archivos de origen.

Pueden ser de colores, no de colores, de múltiples formas, tamaños, lo que sea.

Sin embargo, puede dejar que Illustrator (o lo que sea) lo guarde, con todo el cruft que viene con el viaje:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
<g>
	<path d="M50.049,0.3c14.18,0.332,25.969,5.307,35.366,14.923S99.675,36.9,100,51.409c-0.195,11.445-3.415,21.494-9.658,30.146 - yadda yadda yadda"/>
</g>
</svg>

Combinar los archivos .svg

Puede hacer esto manualmente si lo desea. Lo he hecho. Ni siquiera tiene que mirar el archivo final. Solo llámalo svg-defs.svg o algo.

Debería ser solo un <svg> etiqueta, con una <defs> etiqueta (que solo significa que está definiendo cosas para usar más adelante), y luego un montón de <g> (grupo) etiquetas. Cada <g> La etiqueta tendrá una identificación única y envolverá todas las rutas y demás para cada icono.

<svg>
  <defs>

    <g id="shape-icon-1">
      <!-- all the paths and shapes and whatnot for this icon -->
    <g>

    <g id="shape-icon-2">
      <!-- all the paths and shapes and whatnot for this icon -->
    <g>

    <!-- etc -->

  </defs>
</svg>

Resulta <symbol> es probablemente una mejor opción que <g>. ¡Lee todos los detalles!

Una vez más, puede hacerlo a mano, pero por supuesto que es un poco laborioso. Fabrice Weinberg ha creado un complemento Grunt llamado grunt-svgstore que automatiza esto.

Si nunca ha usado Grunt, puede hacerlo. Aquí tienes un screencast para que comiences.

Puedes instalarlo con:

npm install grunt-svgstore --save-dev

Asegúrese de que la tarea esté disponible con:

grunt.loadNpmTasks('grunt-svgstore');

Y luego en la configuración:

svgstore: {
  options: {
    prefix : 'shape-', // This will prefix each <g> ID
  },
  default : {
      files: {
        'dest/svg-defs.svg': ['svgs/*.svg'],
      }
    }
  }
},

En el archivo de salida, svg-defs.svg, cada icono (cualquier ruta y material del archivo .svg de origen) se incluirá en un <g> etiqueta con un ID único con prefijo y el nombre del archivo (menos el .svg). Me gusta:

<g id="shape-codepen">

Inyecte ese SVG en la parte superior del documento

Incluirlo literalmente, como:

<!DOCTYPE html>
<html lang="en">

<head>
  ...
</head>

<body>
  <?php include_once("processed/svg-defs.svg"); ?>

O como quieras hacer eso.

Lamentablemente, debe estar en la parte superior, ya que hay un error de Chrome en el que esto no funcionará si se define más adelante. Aunque… hay más en esta historia porque mientras escribo estas palabras, el tema que usa este mismo sitio tiene los íconos definidos en la parte inferior del documento y funciona. Ughkgh confuso.

Usa los íconos donde sea

¡Ahora puedes usarlos donde quieras! Me gusta:

<svg viewBox="0 0 100 100" class="icon shape-codepen">
  <use xlink:href="https://css-tricks.com/svg-sprites-use-better-icon-fonts/#shape-codepen"></use>
</svg>

Tenga en cuenta que grunt-svgstore ahora está usando <symbol> ¡por lo que ni siquiera necesita usar viewBox!

Asegúrese de usar esos nombres de clase en el svg para ajustar su tamaño.

/* Do whatever makes sense here.
   Just know that the svg will be an 
   enormous 100% wide if you don't 
   reign in the width. */
.icon {
  display: inline-block;
  width: 25px;
  height: 25px;
}

Yay: puedes diseñarlos (y sus partes) con CSS

Una de las razones por las que amamos las fuentes de iconos es la capacidad de diseñarlas con CSS. Esta técnica supera el hecho de que hacemos todo lo que podemos allí, y más, porque:

  1. Podemos diseñar todas las partes separadas
  2. SVG tiene aún más cosas que puedes controlar, como filtros y trazos especiales

El svg está (un poco) en el DOM, así que JavaScript también. Aquí hay algunas posibilidades de estilo y una demostración de todo esto en funcionamiento:

Vea el Pen EBHlD de Chris Coyier (@chriscoyier) en CodePen.

Otra forma: IcoMoon

IcoMoon, que es conocido por producir fuentes de iconos, también hace un trabajo fantástico al producir sprites SVG. Después de seleccionar todas las fuentes que desee, haga clic en el botón SVG en la parte inferior y obtendrá ese resultado, incluida una página de demostración con el método SVG en línea.

Soporte del navegador

En el frente de soporte del navegador, las zonas de peligro son IE 8 y hacia abajo, Safari 5 y hacia abajo, iOS 4.3 y hacia abajo, y Android 2.3 y hacia abajo. Pero si su política es “las dos últimas versiones principales”, está buscando un soporte prácticamente del 100%.

Recuerde que los íconos solo pueden usarse como un papel secundario, como siempre acompañados de una palabra. Si ese es el caso, el soporte no es un gran problema. Si estos son independientes y la falta de visualización inutilizaría el sitio, eso es un gran problema.

Probablemente optaría por fuentes de iconos, ya que el soporte es mucho más profundo. Solo asegúrate de hacerlo bien.

Esto va a mejorar mucho

Idealmente, podríamos hacer esto:

<svg viewBox="0 0 100 100" class="icon shape-codepen">
  <use xlink:href="https://css-tricks.com/images/svg-defs.svg#shape-codepen"></use>
</svg>

Esto funciona en algunos navegadores, lo que significa que puede omitir la inclusión en la parte superior del documento. Hacerlo de esta manera significa una solicitud HTTP adicional, pero eso significa que puede utilizar el almacenamiento en caché de manera más eficiente (no el almacenamiento en caché de documentos). En las pruebas, Jonathan Neal descubrió que necesita tener el atributo xmlns en el <svg> para que funcione:

<svg xmlns="http://www.w3.org/2000/svg">

Pero incluso entonces, no hay soporte en ningún IE. A no ser que querías cambiar todo <svg><use> con un <object>, que funciona. Jonathan Neal nuevamente se dio cuenta de esto:

/MSIE|Trident/.test(navigator.userAgent) && document.addEventListener('DOMContentLoaded', function () {
  [].forEach.call(document.querySelectorAll('svg'), function (svg) {
    var use = svg.querySelector('use'); 

    if (use) {
      var object = document.createElement('object');
      object.data = use.getAttribute('xlink:href');
      object.className = svg.getAttribute('class');
      svg.parentNode.replaceChild(object, svg);
    }
  });
});

Su demostración ahora también tiene un método que hace una solicitud Ajax de los contenidos e inyecta eso, lo que permite que los rellenos funcionen en IE 9. No tan eficiente, pero más como un polyfill.

Me imagino algún día directamente <svg><use> enlazar directamente al .svg será el camino a seguir. O incluso tal vez <img> trabajando con identificadores de fragmentos de URL en el SVG.

Los navegadores tratan <use> como la sombra DOM:

Ahora mismo, podemos apuntar, digamos, a un individuo <path> con CSS, como:

.targetting-a-path {
  fill: red;
}

Pero eso afectará a todas las instancias de ese camino. Pensarías que podrías hacer:

svg.shape-version-2 .targetting-a-path {
  fill: red;
}

Pero eso no funciona. Cruza ese límite DOM de sombra. Idealmente, usaría el selector de “sombrero” para romper eso:

svg.shape-version-2 ^ .targetting-a-path {
  fill: red;
}

Pero eso tampoco es compatible todavía y no está del todo claro si así es exactamente como funcionará o no.

Fuentes de iconos “Versus”

Basado en vectores: Corbata

Estilo con CSS: leve ventaja a los sprites SVG (partes de destino, estilo específico de SVG como trazos)

Fracasos extraños: SVG parece simplemente funcionar (cuando es compatible). Las fuentes de iconos parecen fallar de formas extrañas. Por ejemplo, asigna los caracteres a letras normales, luego la carga de la fuente falla y obtiene abundan los caracteres aleatorios. O se asigna al “Área de uso privado” y algunos navegadores deciden volver a asignarlos a personajes realmente extraños como rosas, pero es difícil de replicar. O desea alojar los archivos @ font-face en un CDN, pero eso es de origen cruzado y Firefox lo odia, por lo que necesita que su servidor proporcione los encabezados de origen cruzado correctos, pero su configuración de Nginx no lo está recogiendo correctamente. , SUSPIRO. SVG gana este.

Semántica: No es gran cosa, pero creo que un <svg> tiene un poco más sentido para una imagen que un <span>.

Accesibilidad: ¿Quizás alguien me pueda decir? ¿Podemos / deberíamos dar el <svg> un atributo de título o algo así? O un <text> elemento interior que ocultamos visualmente? Actualizar: el <title> elemento podría hacer. O tal vez el <desc> elemento tal como se utiliza en esta especificación de acceso SVG.

Facilidad de uso: Herramientas como Fontello e IcoMoon son bastante buenas para un flujo de trabajo de fuente de iconos, pero creo que la carpeta llena de SVG con Grunt apretándolos es aún más fácil.

Ian Feather publicó un artículo sobre por qué también se alejaron de las fuentes de iconos y estoy de acuerdo con cada punto.