Combine SVG icon files into one with the stack method.
npm install gulp-stacksvg --save-dev
The following script will combine all SVG sources into a single SVG file with stack method.
import { stacksvg } from "gulp-stacksvg"
import gulp from "gulp"
const { src, dest } = gulp
function makeStack () {
return src(`./src/icons/**/*.svg`)
.pipe(stacksvg({ output: `sprite` }))
.pipe(dest(`./dest/icons`))
}
Option | Description | Default |
---|---|---|
output |
Sets the stack file name. Accepts values both with and without the .svg extension. |
stack.svg |
separator |
Replaces the directory separator for the id attribute. |
_ |
spacer |
Joins space-separated words for the id attribute. |
- |
You just don't have to want it.
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
ofimg
tag — static, - in the
href
of theuse
tag — with the possibility of repainting,
- in
- in styles:
- in
url()
propertiesbackground
— static, - in
url()
propertiesmask
— with the possibility of repainting.
- in
Demo page to prove it.
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
<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;
}
.button--icon_heart {
--icon: url("../icons/stack.svg#heart");
}
.button:hover {
--fill: red;
}
.button::before {
content: "";
width: 1em;
height: 1em;
/* icon shape */
mask: var(--icon) no-repeat center / contain;
/* icon color */
background: var(--fill, orangered);
}
⚠️ Note:
We still need the autoprefixer for the mask property.
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.