Skip to content

Repository files navigation

gulp-stacksvg

License: MIT Changelog 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 gulp createStack

Fragment names

Every icon keeps its own svg element inside the stack, named after the path of the source file relative to the directory the icons were read from:

  • the extension is dropped,
  • the directory separators become underscores,
  • the whitespace characters become hyphens.

So ./src/shared/icons/social/like me.svg becomes social_like-me, and the fragment is referenced as ./dist/shared/icons/stack.svg#social_like-me.

Two icons whose paths collapse to the same name — social/like.svg and social_like.svg, for instance — abort the build, since the stack has no way to tell such fragments apart.

Identifiers used inside an icon are renamed to <fragment name>_<number>, so that icons declaring the same gradient, mask or filter stay independent once stacked. Do not rely on these from the outside: the numbering follows the document order of the icon and shifts whenever the icon changes.

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

About

Combine svg files into one with stack method

Topics

Resources

Stars

16 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages