I have two implementations of consuming the same SVG content: one through a <use>
element and one through an <img>
. Despite the same content, viewbox, and sizing on both, the <use>
element comes up shorter -- whereas the <img>
is 160x160
, <use>
is 150x122
. For the life of me I cannot seem to find an answer as to why this is.
The problem I'm looking to solve is to merge 10 or so individual SVG files, consumed via an <img>
, into a singular sprite sheet to avoid unnecessary network requests (they're always consumed together, making this a perfect use for sprites). However, the sizing doesn't match up when switching to the sprite sheet.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
div {
display: flex;
flex-direction: column;
max-width: 10rem;
}
img, svg {
width: 100%;
}
</style>
</head>
<body>
<div>
<svg>
<use href="./icon-sprite.svg#icon" />
</svg>
<img src="./icon.svg" />
</div>
</body>
</html>
icon-sprite.svg
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="icon" viewBox="0 0 54 54">
<path d="M52 5H2C.9 5 0 5.9 0 7v40c0 1.1.9 2 2 2h50c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zM1 7c0-.55.45-1 1-1h50c.55 0 1 .45 1 1v9H1zm52 40c0 .55-.45 1-1 1H2c-.55 0-1-.45-1-1V17h52z" fill="#37474f" />
<path d="M6 8.5a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5S5.17 9.5 6 9.5s1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm6-4a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm6-4a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM48 10c0-.55-.45-1-1-1H35c-.55 0-1 .45-1 1v2c0 .55.45 1 1 1h12c.55 0 1-.45 1-1zm-1 2H35v-2h12zM29.8 29.58l3.2 2.28V44c0 1.65 1.35 3 3 3s3-1.35 3-3V31.86l3.2-2.28c.44-.32.8-1.03.8-1.58v-5c0-.55-.32-1.32-.7-1.7L39 18v6l-3 2-3-2v-6l-3.3 3.3c-.38.38-.7 1.15-.7 1.7v5c0 .55.36 1.26.8 1.58zM30 23c0-.28.2-.8.4-1l1.6-1.6v4.15l.45.3 3 2 .55.36.56-.37 3-2 .44-.3V20.2l1.6 1.7c.2.2.4.82.4 1.1v5c0 .23-.2.63-.4.77l-3.18 2.27-.42.3V44c0 1.1-.9 2-2 2s-2-.9-2-2V31.34l-.42-.3-3.18-2.27c-.2-.14-.4-.54-.4-.77z" fill="#37474f" />
<path stroke-miterlimit="10" d="M36 44V33" fill="#b2ff59" stroke="#37474f" stroke-linecap="round" />
<path d="M27 36h-4V19h-8v17h-4l8 11zm-12 1h1V20h6v17h3.04L19 45.3 12.96 37z" fill="#37474f" />
</symbol>
</svg>
icon.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54">
<path d="M52 5H2C.9 5 0 5.9 0 7v40c0 1.1.9 2 2 2h50c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zM1 7c0-.55.45-1 1-1h50c.55 0 1 .45 1 1v9H1zm52 40c0 .55-.45 1-1 1H2c-.55 0-1-.45-1-1V17h52z" fill="#37474f" />
<path d="M6 8.5a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5S5.17 9.5 6 9.5s1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm6-4a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm6-4a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM48 10c0-.55-.45-1-1-1H35c-.55 0-1 .45-1 1v2c0 .55.45 1 1 1h12c.55 0 1-.45 1-1zm-1 2H35v-2h12zM29.8 29.58l3.2 2.28V44c0 1.65 1.35 3 3 3s3-1.35 3-3V31.86l3.2-2.28c.44-.32.8-1.03.8-1.58v-5c0-.55-.32-1.32-.7-1.7L39 18v6l-3 2-3-2v-6l-3.3 3.3c-.38.38-.7 1.15-.7 1.7v5c0 .55.36 1.26.8 1.58zM30 23c0-.28.2-.8.4-1l1.6-1.6v4.15l.45.3 3 2 .55.36.56-.37 3-2 .44-.3V20.2l1.6 1.7c.2.2.4.82.4 1.1v5c0 .23-.2.63-.4.77l-3.18 2.27-.42.3V44c0 1.1-.9 2-2 2s-2-.9-2-2V31.34l-.42-.3-3.18-2.27c-.2-.14-.4-.54-.4-.77z" fill="#37474f" />
<path stroke-miterlimit="10" d="M36 44V33" fill="#b2ff59" stroke="#37474f" stroke-linecap="round" />
<path d="M27 36h-4V19h-8v17h-4l8 11zm-12 1h1V20h6v17h3.04L19 45.3 12.96 37z" fill="#37474f" />
</svg>
To build this into a snippet I had to use an inline SVG for the sprite, to avoid cross-domain security issues. But all I had to do to get the sprite the same size as the image was to add an aspect-ratio: 1/1
.
Note that neither your icon.svg
nor your icon-sprite.svg
have an intrinsic size, so if you do not specify a size, you are relying on the browser default behaviour which may vary from browser to browser. Your CSS specifies the width of the SVGs (100% of a flexbox which is 10em wide), but not the height. I believe the spec does say that a user agent should use a default size for an SVG if the size is not specified. It seems that, in my browser at least, the regular SVG defaults to an aspect-ratio of 1:1 when the height is not specified, whereas the sprite seems to default to zero height.
Not sure why you were getting different results, but it could be browser-dependent. I am using Safari on a Mac. I tried in Chrome also and the sprite doesn’t need the aspect-ratio to be specified manually.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
div {
display: flex;
flex-direction: column;
max-width: 10rem;
gap: 1em;
}
img, svg {
width: 100%;
}
</style>
</head>
<body>
<svg style="display: none">
<defs>
<symbol id="icon" viewBox="0 0 54 54">
<path d="M52 5H2C.9 5 0 5.9 0 7v40c0 1.1.9 2 2 2h50c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zM1 7c0-.55.45-1 1-1h50c.55 0 1 .45 1 1v9H1zm52 40c0 .55-.45 1-1 1H2c-.55 0-1-.45-1-1V17h52z" fill="#37474f" />
<path d="M6 8.5a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5S5.17 9.5 6 9.5s1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm6-4a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm6-4a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5zm0 4c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM48 10c0-.55-.45-1-1-1H35c-.55 0-1 .45-1 1v2c0 .55.45 1 1 1h12c.55 0 1-.45 1-1zm-1 2H35v-2h12zM29.8 29.58l3.2 2.28V44c0 1.65 1.35 3 3 3s3-1.35 3-3V31.86l3.2-2.28c.44-.32.8-1.03.8-1.58v-5c0-.55-.32-1.32-.7-1.7L39 18v6l-3 2-3-2v-6l-3.3 3.3c-.38.38-.7 1.15-.7 1.7v5c0 .55.36 1.26.8 1.58zM30 23c0-.28.2-.8.4-1l1.6-1.6v4.15l.45.3 3 2 .55.36.56-.37 3-2 .44-.3V20.2l1.6 1.7c.2.2.4.82.4 1.1v5c0 .23-.2.63-.4.77l-3.18 2.27-.42.3V44c0 1.1-.9 2-2 2s-2-.9-2-2V31.34l-.42-.3-3.18-2.27c-.2-.14-.4-.54-.4-.77z" fill="#37474f" />
<path stroke-miterlimit="10" d="M36 44V33" fill="#b2ff59" stroke="#37474f" stroke-linecap="round" />
<path d="M27 36h-4V19h-8v17h-4l8 11zm-12 1h1V20h6v17h3.04L19 45.3 12.96 37z" fill="#37474f" />
</symbol>
</defs>
</svg>
<div>
<svg style="aspect-ratio: 1/1; border: 2px solid lime;">
<use href="#icon" />
</svg>
<img style="border: 2px solid cyan;" src="https://donald.au/bugs/so-77582685/icon.svg" />
</div>
</body>
</html>