/gulp-stacksvg

Combine svg files into one with stack method

Primary LanguageJavaScriptMIT LicenseMIT

gulp-stacksvg

License: MIT Changelog NPM version Test Status

The gulp plugin to combine svg files into one using the stack method.

Installation

pnpm add -D gulp gulp-stacksvg

Usage

Add the following to your gulpfile.js:

import { stacksvg } from "gulp-stacksvg"
import { dest, src } from "gulp"

export function createStack () {
	return src(`./src/shared/icons/**/*.svg`)
		.pipe(stacksvg())
		.pipe(dest(`./dist/shared/icons`))
}

To combine all icons from ./src/shared/icons/ into the ./dist/shared/icons/stack.svg run:

pnpm exec gulp createStack

Why a stack?

Unlike all other methods for assembling a sprite, the stack does not limit us in choosing how to insert a vector into a page. Take a look at the results of different ways to display fragments of different types of sprites.

We can use the stack in all four possible ways:

  • in markup:

    • in src of img tag — static,
    • in the href of the use tag — with the possibility of repainting,
  • in styles:

    • in url() properties background — static,
    • in url() properties mask — with the possibility of repainting.

Demo page to prove it.

Stack under the hood

This method was first mentioned in a Simurai article on April 2, 2012. But even it uses unnecessarily complex code transformations.

This can be done much easier. In general, the stack is arranged almost like a symbol sprite, but without changing the icon tag (it remains the svg tag, as in the original icon files) and with the addition of a tiny bit of style.

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

	<style>:root svg:not(:target) { display: none }</style>

<svg id="sun" viewBox="0 0 24 24">
	<!-- Inner code of sun icon -->
</svg>

<svg id="heart" viewBox="0 0 24 24">
	<!-- Inner code of heart icon -->
</svg>

<svg id="thumbup" viewBox="0 0 24 24">
	<!-- Inner code of thumbup icon -->
</svg>
</svg>

The magic is in the stack inner style, which shows only the fragment requested by the link, hiding everything else:

:root svg:not(:target) { display: none }

And now the icons from the external sprite are available in the styles heart

<button class="button button--icon_heart" type="button">
	<span class="visually-hidden">Add to favorites</span>
</button>
.button {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;

	&:hover {
		--fill: red;
	}

	&::before {
		content: "";
		width: 1em;
		height: 1em;
		/* icon shape */
		mask: var(--icon) no-repeat center / contain;
		/* icon color */
		background: var(--fill, orangered);
	}

	&:where(.button--icon_heart) {
		--icon: url("../icons/stack.svg#heart");
	}
}

For an icon inserted via mask, simply change the background. Moreover, unlike use, you can draw anything in the background under the mask, for example, a gradient.

More info