Search code examples
htmlsvgsasssprite

How do I use the icon from the .svg sprite directly in the CSS/SCSS?


a customer is swearing and demanding that by 2023 standards I use all icons inside the svg file. And icons both for background images and for normal icons that can be changed.

I am using an svg sprite of the following format:

 <?xml version="1.0" encoding="utf-8"?>
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol fill="none" viewBox="0 0 24 24" id="arrow-up-and-down" xmlns="http://www.w3.org/2000/svg">
      <path d="M10.45 6.72 6.73 3 3.01 6.72M6.73 21V3M13.55 17.281l3.72 3.72 3.72-3.72M17.27 3v18"
        stroke="#29354D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
    </symbol>
   </svg>

To use in the layout I use the following template:

`<svg class="arrow-link__icon">
<use xlink:href="./src/images/svg/symbol/sprite.svg#arrow-up-and-down" />
</svg>`

Everything inserts perfectly! The file is stored separately, so I get the images easily and simply. But what about the styles? How can I take some similar icon and insert it into the styles?

`

&-item__text {
            background: url('../images/svg/symbol/sprite.svg#arrow-up-and-down') top left/cover
                    no-repeat,
                $darkBlue;
            height: 100%;
        }

`

now I'm prescribing the following, but it's not working! I can't find the right answer on the internet and my boss is getting angrier and angrier. Help!


Solution

  • As commented by Robert Longson: you can't reference a <symbol> in <img> sources - same applies to CSS background images.

    For images you can use fragment identifiers – this requires to tweak your sprite svg.
    Sprites for use with fragment identifiers need rendered elements.

    Here is an example of a hybrid sprite svg working both with <use> and <img> elements.

    
    <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <style>
    /**
    * show only targeted element
    * as definded by fragment identifier
    * e.g: sprite.svg#use_up_down
    */
        use {
          display: none;
        }
        use:target {
          display: block;
        }
    </style>
    <!-- icons for use with <use> references -->
        <symbol fill="none" viewBox="0 0 24 24" id="arrow-up-and-down" >
          <path d="M10.45 6.72 6.73 3 3.01 6.72M6.73 21V3M13.55 17.281l3.72 3.72 3.72-3.72M17.27 3v18"
             stroke="#29354D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
        </symbol>
        <symbol fill="none" viewBox="0 0 24 24" id="arrow-up" >
          <path d="M10.45 6.72 6.73 3 3.01 6.72M6.73 21V3"
             stroke="#29354D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
        </symbol>
    
        <symbol fill="none" viewBox="0 0 24 24" id="arrow-down" >
          <path d="M13.55 17.281l3.72 3.72 3.72-3.72M17.27 3v18"
             stroke="#29354D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
        </symbol>
    <!-- icons for use with images - hidden by default -->
        <use id="use_up_down" href="#arrow-up-and-down"  />
        <use id="use_up" href="#arrow-up"  />
        <use id="use_down" href="#arrow-down"  />
    </svg>
    
    
    

    Basically you need to add a <use> instance for each symbol.

    Then you add a stylesheet to hide all use elements except the targeted element.

    use {
      display: none;
    }
    use:target {
      display: block;
    }
    

    Now we can use both sprite concepts:

    <svg class="arrow-link__icon" viewBox="0 0 24 24">
      <use href="sprite.svg#arrow-up-and-down" />
    </svg>
    <img src="sprite.svg#use_up" />
    <img src="sprite.svg#use_down" />
    <!-- nothing selected -->
    <img src="sprite.svg" />
    

    See also plnkr example.