skip to Main Content

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>

2

Answers


  1. 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>
    Login or Signup to reply.
  2. Expanding on enxaneta’s comment:

    Rule 1: <svg> elements don’t adjust their rendered bounding box based on content

    This may be an unsatisfying answer but
    there is no exception to this rule: <svg> won’t auto-fit to content.
    No element will cause the parent svg element to expand its rendered bounding box. (you can retrieve a tight content based bounding box via JS method getBBox())

    A common misconception is to think the <symbol> element’s viewBox is somehow "inherited" to the parent svg when appending a <use> instance (referencing to the symbol). Nope! No exception!

    This can’t work since we can only inherit properties from parent (svg) to child (use) and not the other way round (at least in a HTML/CSS context).

    If you don’t specify either width or height or a viewBox for the parent <svg> element – the browser will render the svg with a default of 300×150 px.

    However, if all your icons are placed in a square bounding box you can as well set a css rule to specify a width and length.

    svg {
      border: 1px solid #ccc
    }
    
    .icon {
      font-size: 150px;
      width: 1em;
      height: 1em;
    }
    <h3>Original icon (default: rendered at 100% width)</h3>
    <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>
    
    <h3>No svg dimensions specified (default: 300x150)</h3>
    <svg>
      <use href="#icon" />
    </svg>
    
    <h3>No symbol viewbox specified (default: 300x150)</h3>
    <svg>
      <use href="#iconNoViewBox" />
    </svg>
    
    <h3>symbol viewbox default(300x150)</h3>
    <svg>
      <use href="#iconDefaultViewBox" />
    </svg>
    
    <h3>svg square dimensions specified via css</h3>
    <svg class="icon">
      <use href="#icon" />
    </svg>
    
    <svg xmlns="http://www.w3.org/2000/svg" style="position:absolute; width:0; height:0; visibility:hidden">
      <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>
    
      <symbol id="iconNoViewBox" fill="red">
        <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" />
        <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>
    
      <symbol id="iconDefaultViewBox" viewBox="0 0 300 150">
        <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>

    All in all: either copy viewBox attribute values from symbol to svg instances or define dimensions via css.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search