Logotipo de Zephyrnet

Cómo hice un sistema de iconos con propiedades personalizadas de CSS

Fecha:

SVG es el mejor formato para íconos en un sitio web, hay no hay duda de eso. Le permite tener íconos nítidos sin importar la densidad de píxeles de la pantalla, puede cambiar los estilos del SVG al pasar el mouse e incluso puede animar los íconos con CSS o JavaScript.

Hay muchas formas de incluir un SVG en una página y cada técnica tiene sus propias ventajas y desventajas. Durante los últimos dos años, he estado usando una función de Sass para importar directamente mis íconos en mi CSS y evitar tener que estropear mi marcado HTML.

Tengo una lista de Sass con todos los códigos fuente de mis íconos. Luego, cada ícono se codifica en un URI de datos con una función Sass y se almacena en un propiedad personalizada en la raíz de la página.

TL; DR

Lo que tengo para ti aquí es una función de Sass que crea una biblioteca de iconos SVG directamente en tu CSS.

El código fuente SVG se compila con la función Sass que los codifica en URI de datos y luego almacena los íconos en propiedades personalizadas de CSS. Luego puede usar cualquier ícono en cualquier lugar de su CSS como si fuera una imagen externa.

Este es un ejemplo extraído directamente del código de mi sitio personal:

.c-filters__summary h2:after {
  content: var(--svg-down-arrow);
  position: relative;
  top: 2px;
  margin-left: auto;
  animation: closeSummary .25s ease-out;
}

De demostración

estructura descarada

/* All the icons source codes */
$svg-icons: (
  burger: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0...'
);

/* Sass function to encode the icons */
@function svg($name) {
  @return url('data:image/svg+xml, #{$encodedSVG} ');
}

/* Store each icon into a custom property */
:root {
  @each $name, $code in $svg-icons {
    --svg-#{$name}: #{svg($name)};
  }
}

/* Append a burger icon in my button */
.menu::after {
  content: var(--svg-burger);
}		

Esta técnica tiene ventajas y desventajas, así que tómelas en cuenta antes de implementar esta solución en su proyecto:

Para Agencias y Operadores

  • No hay solicitudes HTTP para los archivos SVG.
  • Todos los iconos se almacenan en un solo lugar.
  • Si necesita actualizar un ícono, no tiene que revisar cada archivo de plantilla HTML.
  • Los íconos se almacenan en caché junto con su CSS.
  • Puede editar manualmente el código fuente de los iconos.
  • No contamina su HTML al agregar marcas adicionales.
  • Aún puede cambiar el color o algún aspecto del icono con CSS.

Desventajas

  • No puede animar o actualizar una parte específica del SVG con CSS.
  • Cuantos más íconos tenga, más pesado será su archivo compilado CSS.

Principalmente uso esta técnica para íconos en lugar de logotipos o ilustraciones. Un SVG codificado siempre va a ser más pesado que su archivo original, por lo que sigo cargando mi SVG complejo con un archivo externo, ya sea con un etiqueta o en mi CSS con url(path/to/file.svg).

Codificación de SVG en URI de datos

La codificación de su SVG como URI de datos no es nueva. En realidad Chris Coyier escribió una publicación sobre esto hace más de 10 años para explicar cómo usar esta técnica y por qué deberías (o no deberías) usarla.

Hay dos formas de usar un SVG en su CSS con URI de datos:

  • Como una imagen externa (usando background-image,imagen de borde,imagen-estilo-lista,…)
  • Como el contenido de un pseudo elemento (p. ej. ::before or ::after)

Aquí hay un ejemplo básico que muestra cómo usar esos dos métodos:

El problema principal con esta implementación en particular es que tiene que convertir el SVG manualmente cada vez que necesita un ícono nuevo y no es muy agradable tener esta larga cadena de código ilegible en su CSS.

¡Aquí es donde Sass viene al rescate!

Usando una función Sass

Al usar Sass, podemos simplificar nuestra vida copiando el código fuente de nuestro SVG directamente en nuestra base de código, dejando que Sass los codifique correctamente para evitar cualquier error del navegador.

Esta solución está inspirada principalmente en una función existente desarrollada por Threespot Media y disponible en su repositorio.

Estos son los cuatro pasos de esta técnica:

  • Cree una variable con todos sus iconos SVG en la lista.
  • Enumere todos los caracteres que deben omitirse para un URI de datos.
  • Implemente una función para codificar los SVG en un formato de URI de datos.
  • Usa tu función en tu código.

1. Lista de iconos

/**
* Add all the icons of your project in this Sass list
*/
$svg-icons: (
  burger: ''
);

2. Lista de caracteres escapados

/**
* Characters to escape from SVGs
* This list allows you to have inline CSS in your SVG code as well
*/
$fs-escape-chars: (
  ' ': '%20',
  ''': '%22',
  '"': '%27',
  '#': '%23',
  '/': '%2F',
  ':': '%3A',
  '(': '%28',
  ')': '%29',
  '%': '%25',
  '': '%3E',
  '': '%5C',
  '^': '%5E',
  '{': '%7B',
  '|': '%7C',
  '}': '%7D',
);

3. Función de codificación

/**
* You can call this function by using `svg(nameOfTheSVG)`
*/
@function svg($name) {
  // Check if icon exists
  @if not map-has-key($svg-icons, $name) {
    @error 'icon “#{$name}” does not exists in $svg-icons map';
    @return false;
  }

  // Get icon data
  $icon-map: map-get($svg-icons, $name);

  $escaped-string: '';
  $unquote-icon: unquote($icon-map);
  // Loop through each character in string
  @for $i from 1 through str-length($unquote-icon) {
    $char: str-slice($unquote-icon, $i, $i);

    // Check if character is in symbol map
    $char-lookup: map-get($fs-escape-chars, $char);

    // If it is, use escaped version
    @if $char-lookup != null {
        $char: $char-lookup;
    }

    // Append character to escaped string
    $escaped-string: $escaped-string + $char;
  }

  // Return inline SVG data
  @return url('data:image/svg+xml, #{$escaped-string} ');
}		

4. Agrega un SVG en tu página

button {
  &::after {
    /* Import inline SVG */
    content: svg(burger);
  }
}

Si ha seguido esos pasos, Sass debería compilar su código correctamente y generar lo siguiente:

button::after {
  content: url("data:image/svg+xml, %3Csvg%20xmlns=%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox=%270%200%2024.8%2018.92%27%20width=%2724.8%27%20height=%2718.92%27%3E%3Cpath%20d=%27M23.8,9.46H1m22.8,8.46H1M23.8,1H1%27%20fill=%27none%27%20stroke=%27%23000%27%20stroke-linecap=%27round%27%20stroke-width=%272%27%2F%3E%3C%2Fsvg%3E ");
}		

Propiedades personalizadas

El Sass ahora implementado svg() la función funciona muy bien. ¡Pero su mayor defecto es que un icono que se necesita en varios lugares de su código se duplicará y podría aumentar mucho el peso de su archivo CSS compilado!

Para evitar esto, podemos almacenar todos nuestros íconos en Variables CSS y use una referencia a la variable en lugar de generar el URI codificado cada vez.

Mantendremos el mismo código que teníamos antes, pero esta vez primero mostraremos todos los íconos de la lista de Sass en la raíz de nuestra página web:

/**
  * Convert all icons into custom properties
  * They will be available to any HTML tag since they are attached to the :root
  */

:root {
  @each $name, $code in $svg-icons {
    --svg-#{$name}: #{svg($name)};
  }
}

Ahora, en lugar de llamar al svg() función cada vez que necesitamos un icono, tenemos que usar la variable que se creó con el --svg prefijo.

button::after {
  /* Import inline SVG */
  content: var(--svg-burger);
}

Optimizando sus SVG

Esta técnica no proporciona ninguna optimización en el código fuente del SVG que está utilizando. Asegúrese de no dejar código innecesario; de lo contrario, también se codificarán y aumentarán el tamaño de su archivo CSS.

Puedes comprobar esta gran lista de herramientas e información sobre cómo optimizar correctamente su SVG. Mi herramienta favorita es la de Jake Archibald. SVGOMG – simplemente arrastre su archivo allí y copie el código generado.

Bonificación: actualizar el ícono al pasar el mouse

Con esta técnica, no podemos seleccionar con CSS partes específicas del SVG. Por ejemplo, no hay manera de cambiar el fill color del icono cuando el usuario desplaza el botón. Pero hay algunos trucos que podemos usar con CSS para poder modificar el aspecto de nuestro ícono.

Por ejemplo, si tiene un ícono negro y desea que sea blanco al pasar el mouse, puede usar el invert() filtro CSS. También podemos jugar con el hue-rotate() filtrar.

¡Eso es!

Espero que encuentre útil esta pequeña función de ayuda en sus propios proyectos. Déjame saber lo que piensas del enfoque. ¡Me interesaría saber cómo mejorarías esto o cómo lo abordarías de manera diferente!

punto_img

Información más reciente

punto_img