Cómo funcionan los identificadores de fragmentos SVG | Programar Plus

He hablado un poco sobre los SVG. <use> por aquí y usándolo para construir un sistema de iconos. La belleza de <use> es que puede hacer referencia solo a una parte de algún SVG definido en otro lugar y dibujar solo esa parte en otro lugar. Esa capacidad le permite construir un sistema completo a partir de ella, resolviendo el problema de “muchas imágenes en una solicitud, porque es súper eficiente” que hemos resuelto en el pasado con sprites CSS y fuentes de iconos.

Pero <use> significa SVG en línea. No le ayuda cuando quiere usar una parte de un SVG más grande en SVG-as-<img> o SVG comobackground-image. Ahí es donde entran los identificadores de fragmentos.

Preparando el SVG para ello

Una forma de hacer esto es diseñar el SVG (sprite, supongo, llamémoslo simplemente sprite) como un sprite gráfico “CSS”.

Específicamente lo estamos haciendo de esta manera, porque en última instancia vamos a cambiar algunos viewBox números alrededor para revelar solo una parte de esta imagen, tal como solíamos hacer con los sprites CSS.

En esta pequeña mini demostración, usamos tres íconos de 32 × 32 cada uno. Entonces el documento es 32 × 96. Podríamos pensar en las travesuras de viewBox de esta manera:

Vista del documento completo 0 0 32 96
Solo muestra la vista del icono superior 0 0 32 32
Solo muestra la vista del icono central 0 32 32 32
Solo muestra la vista del icono inferior 0 64 32 32

El viewBox el atributo va: izquierda, arriba, ancho, alto. Tenga en cuenta que el segundo atributo, la parte superior, sube 32 cada vez. Solo mostramos una parte diferente de todo el documento.

Agregar esos viewBox especiales en el propio SVG

Puedes dejar esos especiales, específicos viewBox valores en el SVG en un <view> elemento, que es específicamente para esto:

<view id="icon-clock-view" viewBox="0 0 32 32" />
<view id="icon-heart-view" viewBox="0 32 32 32" />
<view id="icon-arrow-right-view" viewBox="0 64 32 32" />

Ahora podremos hacer referencia y usar esos valores de otros lugares.

El <view> Los elementos pueden ser independientes como este, o pueden envolver otros elementos, en cuyo caso viewBox se mantiene cuando la identificación coincide, por lo que

<!-- this viewBox takes over if current fragment identifer is #match-me -->
<view id="match-me" viewBox="0 64 32 32">
  <rect ...>
</view>

Demostración de este tipo de cosas en la especificación.

Sintaxis para HTML

Para aplicar esos especiales viewBox valores a SVG-as-<img>, podrías hacerlo así:

<!-- top icon -->
<img src="https://css-tricks.com/svg-fragment-identifiers-work/sprite.svg#svgView(viewBox(0, 0, 32, 32))" alt="">

O, si configuras <view> elementos ya, puede hacer referencia a ellos por su nombre:

<!-- middle icon -->
<img src="https://css-tricks.com/svg-fragment-identifiers-work/sprite.svg#icon-heart-view" alt="">

Sintaxis de CSS

Puedes declarar un especial viewBox justo en la ruta de la imagen en el CSS:

.icon-clock {
  background: url("https://css-tricks.com/svg-fragment-identifiers-work/sprite.svg#svgView(viewBox(0, 0, 32, 32))") no-repeat;
}

O hacer referencia a un <view> elemento si los tiene configurados:

.icon-clock {
  background: url(sprite.svg#icon-clock-view) no-repeat;
}

Aunque … si está usando SVG a través de CSS de esta manera y se tomó la molestia de configurar el SVG todo espaciado de esta manera, es posible que desee usar la técnica de sprite CSS y cambiar el fondo:

.icon-heart {
  background: url("sprite.svg") no-repeat;
  background-size: 32px 96px;
  background-position: 0 -32px;
}

Solo quiero apilar los íconos uno encima del otro.

Si todos los iconos tienen el mismo viewBox y esencialmente solo desea ocultarlos / mostrarlos según sea necesario, esto puede ser un poco más fácil.

Diseñe todos en el mismo espacio (o use una herramienta de construcción que lo haga o lo que sea). Aquí, pongo cada ícono en su propio grupo con una identificación única.

El truco para hacer que el ocultar / mostrar funcione es incrustar algo de CSS que 1) oculta todo 2) revela el que tiene un identificador de fragmento coincidente. CSS está preparado para el trabajo, debido a la :target selector.

Todos juntos en el SVG:

<defs>
  <style>
    g {
      display: none;
    }
    g:target {
      display: inline;
    }
  </style>
</defs>

<g id="icon-clock">
  <path d="M20.6,23.3L14,16.7V7.9h4v7.2l5.4,5.4L20.6,23.3z M16-0.1c-8.8,0-16,7.2-16,16s7.2,16,16,16s16-7.2,16-16S24.8-0.1,16-0.1z
		 M16,27.9c-6.6,0-12-5.4-12-12s5.4-12,12-12s12,5.4,12,12S22.6,27.9,16,27.9z"/>
</g>
<g id="icon-heart">
  <path d="M32,11.2c0,2.7-1.2,5.1-3,6.8l0,0L19,28c-1,1-2,2-3,2s-2-1-3-2L3,18c-1.9-1.7-3-4.1-3-6.8C0,6.1,4.1,2,9.2,2
		c2.7,0,5.1,1.2,6.8,3c1.7-1.9,4.1-3,6.8-3C27.9,1.9,32,6.1,32,11.2z"/>
</g>
<g id="icon-arrow-right">
  <path d="M32,15.9l-16-16v10H0v12h16v10L32,15.9z"/>
</g>

Soporte del navegador

¿Puedo usar el soporte de pistas para el identificador de fragmentos? Desafortunadamente, no es tan simple como funciona o no porque, dependiendo del navegador, puede funcionar en HTML y no en CSS o tener peculiaridades.

Aquí está mi página de prueba:

Consulte los identificadores de fragmentos de SVG de lápiz en HTML y CSS de Chris Coyier (@chriscoyier) en CodePen.

No he hecho notas de soporte del navegador súper detalladas para esto, pero aquí están los aspectos más destacados:

  • Firefox hace todo bien.
  • IE 11 hace todo bien. IE 9 y 10 son un poco raros con background-position (aplastando) pero por lo demás funciona con todos.
  • Las versiones actuales de Chrome / Safari / Opera (38/8/25) manejan todo el HTML <img> técnicas bien, pero ninguna de las técnicas CSS, incluida la background-position una. Pre-Blink Opera fue lo mismo, curiosamente. Actualizar: Si el <svg> referenciado tiene los atributos de ancho y alto correctos, todos los métodos funcionan como se esperaba. Al menos lo hace ahora, a partir de Chrome (56) / Opera.
  • Lo único que puede manejar iOS 8.1 es <img> haciendo referencia a un <view>.
  • Lo único que hace bien Android 4.4 es la posición de fondo (la que realmente no usa identificadores de fragmentos). Android 5 coincide con Chrome / Safari / Opera actual como arriba.

¡Enlace!

  • Especificaciones
  • SVG Stacks de Simuari, que apunta a una demostración de Erik Maelström y una demostración de Bear Travis.
  • Demo de Jorge Aznar
  • Mejores Sprites SVG con identificadores de fragmentos de Peter Gasston
  • Hojas de Sprite SVG de Bear Travis