Curso de Fundamentos de Sass: Crea tu Primera Landing Page

Toma las primeras clases gratis

Íconos SVG desde assets con color y tamaño controlados desde Sass

En el curso, la profesora pega el código del SVG directamente dentro del HTML para poder cambiarle el stroke. Funciona y es ideal para aprender, pero tiene un costo: el HTML se llena de código largo, y si quieres cambiar el color de los íconos, tienes que editarlos uno por uno.

En este tutorial vamos a mantener los .svg en la carpeta assets/svg/, dejar el HTML limpio y controlar el color y el tamaño de todos los íconos desde un solo lugar en Sass. Es una práctica mucho más cercana a lo que se hace en proyectos reales.

Qué vas a lograr

  • Un HTML sin código SVG pegado.
  • Cambiar el color de todos los íconos editando una sola variable.
  • Cambiar el tamaño (ancho y alto) de todos los íconos editando una sola variable.
  • Agregar un ícono nuevo escribiendo una sola línea.

Estructura de carpetas

Se asume la misma estructura del curso:

eco-store-platzi/
├── assets/
│   └── svg/
│       ├── heart.svg
│       ├── profile.svg
│       └── shopping-cart.svg
├── css/
│   └── main.css      (se genera solo al compilar)
├── scss/
│   └── main.scss
└── index.html

El punto de partida

Este es el navbar tal como queda siguiendo la clase, usando <img> para traer los SVG desde assets.

HTML:

<nav class="navbar">
	<p>Eco-store</p>
	<div class="icons">
		<button class="profile">
			<img src="assets/svg/profile.svg" alt="" /></button
		><button class="whislist">
			<img src="assets/svg/heart.svg" alt="" /></button
		><button class="cart">
			<img src="assets/svg/shopping-cart.svg" alt="" />
		</button>
	</div>
</nav>

SCSS:

nav {
	width: 100%;
	height: 300px;
	p {
		font-size: 1.5em;
		padding-left: 30px;
	}
	.icons {
		display: flex;
		button {
			background: none;
			border-style: none;
		}
	}
}

El problema

Cuando un SVG entra por <img>, el navegador lo trata como una imagen cerrada. Tu CSS no puede entrar a su interior para modificar stroke ni fill. No es un error de tu selector, es una barrera del navegador.

Por eso la profesora los pega inline: dentro del HTML sí son accesibles. Pero nosotros queremos mantenerlos en assets.

La solución: usar el SVG como máscara

La idea es dejar de ver el SVG como una imagen y usarlo como un molde:

  1. El botón tiene un background-color sólido. Ese color lo controlamos desde Sass.
  2. El SVG se aplica con la propiedad mask. Solo se ve el color en las zonas donde el SVG tiene trazo o relleno. El resto queda transparente.

El resultado es el mismo ícono, pero ahora su color depende de tu CSS y no del archivo.

Paso 1: limpiar el HTML

Elimina los <img>. El ícono ya no vive en el HTML, vive en el CSS.

<nav class="navbar">
	<p>Eco-store</p>
	<div class="icons">
		<button class="profile"></button>
		<button class="whislist"></button>
		<button class="cart"></button>
	</div>
</nav>

Paso 2: agregar las variables

Al inicio de tu main.scss, antes del bloque nav, agrega estas dos variables:

$icon-color: #2e7d32;
$icon-size: 24px;

Cambia el color por el de tu paleta. Estas dos líneas controlan el aspecto de todos los íconos del navbar.

Paso 3: agregar el mixin

Justo debajo de las variables, agrega este mixin:

@mixin icon-mask($file) {
	-webkit-mask: url("../assets/svg/#{$file}") no-repeat center / contain;
	mask: url("../assets/svg/#{$file}") no-repeat center / contain;
}

Un mixin es un bloque de estilos reutilizable. Lo necesitamos porque las líneas de la máscara serían idénticas en los tres botones; solo cambia el nombre del archivo. Por eso el mixin recibe el nombre como parámetro ($file) y lo inserta dentro de la ruta con #{$file}, que se llama interpolación.

Si quieres profundizar en mixins, parámetros e interpolación, lo veremos con más detalle en el Curso de Fundamentos de Sass de Platzi, en la sección de Mixins.

Qué hace cada parte de la máscara:

  • url("../assets/svg/..."): ruta del SVG. Es relativa al CSS compilado (css/main.css), no al .scss. Desde css/ subimos un nivel con ../ y entramos a assets/svg/.
  • no-repeat: evita que el ícono se repita como mosaico.
  • center: lo centra dentro del botón.
  • contain: lo escala para que quepa completo sin deformarse.
  • La versión con -webkit- es por compatibilidad con navegadores basados en Chromium y Safari.

Paso 4: actualizar el bloque nav

Este es tu SCSS del navbar con los cambios aplicados:

nav {
	width: 100%;
	height: 300px;
	p {
		font-size: 1.5em;
		padding-left: 30px;
	}
	.icons {
		display: flex;
		button {
			background-color: $icon-color;
			border-style: none;
			width: $icon-size;
			height: $icon-size;
		}
		.profile {
			@include icon-mask("profile.svg");
		}
		.whislist {
			@include icon-mask("heart.svg");
		}
		.cart {
			@include icon-mask("shopping-cart.svg");
		}
	}
}

Qué cambió respecto a la versión original

  1. background: none pasó a background-color: $icon-color. Este cambio es obligatorio. La máscara recorta el fondo con la silueta del SVG, así que si el fondo es transparente no hay nada que recortar y no se ve nada.
  2. Se agregaron width y height con $icon-size. Antes, la imagen dentro del botón le daba su tamaño. Ahora el botón está vacío y, si no le damos medidas, colapsa y desaparece. De paso, este es el control del tamaño de todos los íconos.
  3. Se agregaron las tres clases con @include. Cada una le indica al mixin qué archivo usar.
  4. Se mantiene todo lo demás. border-style: none, display: flex y el resto no se tocan.

Cómo usarlo en el día a día

Cambiar el color de todos los íconos: edita $icon-color.

$icon-color: #1b5e20;

Cambiar el tamaño de todos los íconos: edita $icon-size.

$icon-size: 32px;

Agregar un ícono nuevo: pon el archivo en assets/svg/, crea el botón en el HTML y agrega una línea en el SCSS.

<button class="search"></button>
.search {
	@include icon-mask("search.svg");
}

Antes, esto implicaba pegar el SVG completo en el HTML y editar su stroke a mano.

Si algo no funciona

El ícono no aparece. Revisa estas tres cosas en orden:

  1. Abre la página con Live Server, no con doble clic sobre el archivo. Los navegadores basados en Chromium (Chrome, Brave, Edge) bloquean las máscaras cuando la URL empieza con file://. Con Live Server la URL será http://127.0.0.1:5500 y funciona.
  2. Verifica la ruta. Recuerda que es relativa a css/main.css. Si tu carpeta de SVG se llama distinto, ajústala en el mixin.
  3. Confirma que el botón tiene tamaño y color de fondo. Sin width, height y background-color, la máscara no tiene nada que mostrar.

El ícono se ve de otro color del esperado. El color original del archivo SVG se ignora. Lo único que importa es su silueta. El color siempre sale de $icon-color.

Los íconos tienen varios colores. Con mask el resultado es de un solo color. Para íconos de línea como perfil, corazón y carrito no hay problema. Si necesitas íconos multicolor, deberás usar <img> normal o SVG inline.

Accesibilidad: un detalle para mejorar

Los botones quedaron vacíos, así que un lector de pantalla no sabe qué hacen. En el código original los <img alt=""> tampoco lo decían, por lo que no es un retroceso. Pero en un proyecto real se resuelve agregando aria-label a cada botón:

<button class="profile" aria-label="Perfil"></button>
<button class="whislist" aria-label="Lista de deseos"></button>
<button class="cart" aria-label="Carrito"></button>

Extra opcional: evitar repetir las tres clases

Cuando tengas más íconos, puedes recorrerlos con un mapa y @each en lugar de escribir cada clase. Esto lo veremos en la sección de funciones y operadores del curso.

$icons: (
	"profile": "profile.svg",
	"whislist": "heart.svg",
	"cart": "shopping-cart.svg",
);

@each $name, $file in $icons {
	.#{$name} {
		@include icon-mask($file);
	}
}

Con esto, agregar un ícono nuevo es agregar una línea al mapa.

Por qué este enfoque es mejor que pegar el SVG

  • HTML limpio: sin bloques largos de <svg> y <path>.
  • Un solo lugar para cambiar el diseño: el color y el tamaño viven en variables.
  • Fácil de mantener: si un ícono cambia de nombre o carpeta, lo editas en el SCSS y no en cada HTML.
  • Escalable: agregar íconos es una línea de código.

Código completo

El código con todos los cambios implementados está en este gist, para que puedas descargarlo y verlo como documentos completos (index.html y main.scss):

Enlace al gist

Curso de Fundamentos de Sass: Crea tu Primera Landing Page

Toma las primeras clases gratis

0 Comentarios

para escribir tu comentario

Artículos relacionados