Reputation: 824
It's not bad if I load an HTML page
img, svg {
background-color: #eee;
margin: 20px;
}
<div>
<img src="circle.svg"/>
<img src="square.svg"/>
</div>
with just a pair of SVG images
circle.svg
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 400 300" width="400" height="300">
<circle cx="200" cy="150" r="100"
stroke="red" fill="blue" stroke-width="10" />
</svg>
square.svg
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 400 300" width="400" height="300">
<rect x="100" y="50" width="200" height="200"
stroke="green" fill="gray" stroke-width="10" />
</svg>
but with over a hundred SVG images, the server gets excessively hit by requests.
One solution is to serve the static files from a dedicated server, but this only dodges the problem. The number of requests remains high.
How can I bundle many SVG images inside just one?
Upvotes: 1
Views: 4108
Reputation: 824
The following is a combination of gael's and maqam7's answers, with a bug fix and some details.
First, we combine the two SVGs into one. (We write our own script, use an editor's macros, use one of the web sites that do it, or do it by hand.)
sprite.svg
<svg id="mysprite" xmlns="http://www.w3.org/2000/svg">
<symbol id="circle"
viewBox="0 0 400 300"
width="400" height="300">
<circle cx="200" cy="150" r="100"
stroke="red" fill="blue" stroke-width="10" />
</symbol>
<symbol id="square"
viewBox="0 0 400 300"
width="400" height="300">
<rect x="100" y="50" width="200" height="200"
stroke="green" fill="gray" stroke-width="10" />
</symbol>
</svg>
When we want a circle or a square, we use
the xlink:href
attribute (deprecated but continue to use it), which will invoke a sub-sprite.
<div class="container">
<svg>
<use xlink:href="sprite.svg#circle"></use>
</svg>
<svg>
<use xlink:href="sprite.svg#square"></use>
</svg>
</div>
There is no need to include the sprite in the body
<img src="sprite.svg"/>
as the sprite is referenced within each svg
element.
Hence there is no need to hide the global sprite.
#svg-sprite {
display: none;
}
Only the sub-parts appear.
One caveat: Chrome loads an img
and svg
directly, but will refuse to load use
/xlink:href
unless you run a local server.
Remaining issue(s)
I'm not sure this is optimal. It may be that two requests continue to be sent. It's just that the cache will catch the second as identical. No harm is done. Still, loading once via a hidden svg
may be a better approach, if someone can fill in the details.
Upvotes: 1
Reputation: 1235
It sounds like you need an SVG sprite. I use this trick all the time. It's great. Just make your svg
blocks symbol
elements and nest them inside an svg
like this:
<svg id="svg-sprite" xmlns="http://www.w3.org/2000/svg">
<symbol id="svg-circle" viewBox="0 0 400 300" width="400" height="300">
<circle cx="200" cy="150" r="100" stroke="red" fill="blue" stroke-width="10" />
</symbol>
<symbol id="svg-square" viewBox="0 0 400 300" width="400" height="300">
<rect x="100" y="50" width="200" height="200" stroke="green" fill="gray" stroke-width="10" />
</symbol>
</svg>
Note that you don't want the xlmns
attribute on the individual symbol
elements, just the root svg
. And the root svg
doesn't need a viewBox attribute, since that is encoded in the child symbol
elements.
Then you call the symbols elsewhere in the HTML like this via the <use>
tag:
<svg>
<use xlink:href="#svg-circle"></use>
</svg>
Lastly, you need to hide the sprite in CSS:
#svg-sprite {
display: none;
}
Here's a Fiddle to demonstrate. Good luck!
Upvotes: 1
Reputation: 1485
You could use a SVG sprite generator to create one big file with all images aligned in it.
SVG sprite generator will also generate a CSS file in which each individual SVG will be represented with a specific class.
In you HTML you just have to call each image by its class name.
A basic sprite.css could be :
.svg {
background-image: url(sprite.svg) no-repeat;
}
.circle {
background-position: top left;
height:300px;
width: 400px;
}
.square{
background-position: top right;
height:200px;
width: 200px;
}
And then in your html file you could just call:
<div>
<div class="circle"></div>
<div class="square"></div>
</div>
Upvotes: 2