The SVG Re-<use> Case

Case is that you want to re-use an svg element independent from it's declaration. To display it more than once in your html page flow. Or to apply a svg element from a declaration external in your html page.

In short course

  1. Put an svg element inside your html or an external svg file.
  2. Make that svg element invisible by giving it an attribute of display="none"
  3. Add a symbol element inside the svg element, giving it a unique id attribute
  4. Put whatever SVG element renders your SVG inside that symbol element
  5. From your html element flow, use that symbol element by referencing it via <use xlink:href="relativePathToAnExternalSvgFileOrEmpty#theIdFromTheSymbol", sorrounding it with a another svg element

The no-scaling case

The following contained svg elements (text and path) are defined in a <symbol> element, which means that they won’t be directly rendered on the SVG canvas. The SVG document itself, where you defined that symbol, will still be rendered on the page, even if it contains no rendered elements. In order to avoid that, make sure you set display: none on the first SVG. Else it get's displayed and therefore rendered as a HTML Replaced Element.

<svg display="none">
  <symbol id="v-line">
    <text fill="white" x="50" y="-6" transform="rotate(90)" text-anchor="middle">100 px</text>
    <path stroke="white" stroke-width="2" d="M20,0V+100Z"/>
  </symbol>
</svg>

When you <use> a symbol element, the contents of that element are copied, as is, into wherever you place the <use> in the page. This copy is a called a Shadow DOM. The Shadow DOM references a document fragment which is basically just another subtree of nodes elsewhere having it's own scope encapsulated.

Now we can render multiple instances of the icon by a <use> element with a xlink:href="#theIdFromTheSymbol" attribute, whose value references the id of the symbol element above.

<svg class="line" style="vertical-align: top;">
    <use href="#v-line"/>
</svg>
<!-- 
--><svg class="line" style="vertical-align: baseline;">
    <use href="#v-line"/>
</svg>
.line {
  display: inline;
  width: 24px;
  height: 100px;
  font-size: 0.125em;
  font-weight: 1000;
  color: $color-block-attent;
}

Note that neither the viewbox nor the width and height attributes on the <svg> element itself is set. Hence the SVG has no scaling applied and all measures are interpreted as absolute in pixels. When the width and height were specified into a css class referenced via the class attribute, the SVG was rendered in a rectangle that is 24px wide and 100px tall.

The scaling case

Do not drop the width and height in the svg element

So why would you want to set explicit dimensions on your <svg> when what you’re really trying to do is make the SVG fluid, right?

Ideally, we should make our SVGs responsive while also catering for any worst case scenarios where our styles are ignored or simply not applied for any reason. By taking advantage of the SVG style inheritance tree, we can make our SVGs responsive while simultaneously planning for worst case scenarios, and providing a decent, less broken, fallback.

  • Browsers that don’t support the applied technique
  • Slow on loading CSS
  • SVG displayed as replaced element
  • SVG displayed at 100% x 100% of browser viewport
  • Default fallback on SVG styles; fill and stroke will be black

In order to avoid the no-CSS scaling issue, all you need to do is NOT remove the width and height attributes from the SVG. And, specify your desired width and height values in the CSS.

What width and height to apply as default

Use the same dimensions as the viewBox dimensions, but they don’t have to be identical. But they have to be in the same ratio as the viewBox dimension.

.icon {
    width: 100px;
    height: 125px;
}

What width and height to apply as overriding dimensions

Let it be fluid and fill out its container’s width?

svg {
    width: 100%;
    height: 100%;
}

Scale it in proportion to the text it is inline with?

svg {
    width: 1em;
    height: 1em;
    /* maybe even... */
    color: currentColor;
}

How to style each re-use differently

To re-use an element mutliple times and style each occurance differently; leverage CSS Variables.

Do it by overriding SVG fill colors with CSS Variables.

<svg style="display: none">
    <symbol id="robot" viewBox="0 0 340 536">
        <path d="..." fill="#fff" />
        <path d="..." fill="#D1312C" />
        <path d="..." fill="#1E8F90" style="fill: var(--primary-color)" />
        <path d="..." fill="#1E8F90" style="fill: var(--primary-color)" />
        <path d="..." fill="#fff" />
        <path d="..." fill="#6A4933" style="fill: var(--tertiary-color)" />
        <path d="..." fill="#1E8F90" style="fill: var(--primary-color)" />
        <path d="..." fill="#6A4933" style="fill: var(--tertiary-color)" />
        <path d="..." fill="#fff" />
        <path d="..." fill="#6A4933" style="fill: var(--tertiary-color)" />
        <path d="..." fill="#F2B42B" style="fill: var(--secondary-color)" />
        <path d="..." fill="#fff" />

        <!-- rest of the shapes -->
    </symbol>
</svg>

References

https://24ways.org/2014/an-overview-of-svg-sprite-creation-techniques/

https://tympanus.net/codrops/2015/07/16/styling-svg-use-content-css/

results matching ""

    No results matching ""