How to handle Sketch exported SVG with ids

Viewed 4247

I want to use svg icons in my page. The designers I work with use Sketch to design the image and export the result in svg. Sketch adds various id tags to the exported code (note the id="Page-1", id="My-Star" and id="Star-1" attributes):

<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
            <g id="My-Star" stroke="#979797" fill="#D8D8D8">
                <polygon id="Star-1" points="11.9860934 18.5835921 5.4876995 22 6.7287823 14.763932 1.47147118 9.63932023 8.73689646 8.58359214 11.9860934 2 15.2352904 8.58359214 22.5007157 9.63932023 17.2434045 14.763932 18.4844873 22 "></polygon>
            </g>
        </g>
    </svg>

I include the svg directly in the html. By doing this, I introduce the same id multiple times. Besides the invalid html that is a result of this way of working, I need to style the svg elements based on ids. This is a bad practice.

I use css to style the svgs, take a look at an example

The question:
Is there a way to replace the ids with classes when exporting svgs from Sketch? Is there some plugin or setting I can give to the designers? If not, what is the optimal workflow in receiving svg assets from designers and using it in the page?

5 Answers

I highly recommend adding svgo to your workflow if you're dealing with SVGs exported via Sketch. Not only will the tool eliminate unused IDs (you're still on the hook for manually resolving IDs that are used by the SVG), it will also optimize the SVG better than the default SVG export.

If you're doing this often, adding SVGO to your dev/build process (see examples); if you just want to take it for a test run, however, there's also a web-based GUI: https://jakearchibald.github.io/svgomg/

I fixed it by adding a different prefix to the IDs included on each SVG. To avoid glitches, it hides the SVGs until the prefixes are added to the IDs.

CSS:

    svg {
        opacity: 0;
        transition: opacity .5s ease-in-out;
    }
    svg.svg-visible {
        opacity: 1;
    }

JS:

    function replaceAll(str, find, replace) {
      var escapedFind=find.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
      return str.replace(new RegExp(escapedFind, 'g'), replace);
    }
    
    var svgCounter = 0;
    
    [].forEach.call(document.querySelectorAll('svg'), function(el) {
      var contentReplaced = replaceAll(el.innerHTML,'id="','id="n' + svgCounter); 
      contentReplaced = replaceAll(contentReplaced,'url(#','url(#n' + svgCounter);
      contentReplaced = replaceAll(contentReplaced,'xlink:href="#','xlink:href="#n' + svgCounter);
      el.innerHTML = contentReplaced;
      el.classList.add('svg-visible');
      svgCounter++;
    })

You can also make it cleaner using PHP:

    function inlinesvg($module, $svg) {
        $id = 'svg-' . substr(md5(uniqid(mt_rand(), true)) , 0, 8);
        $file_contents = file_get_contents('./assets/img/'.$module.'/'.$svg.'.svg');
        $file_contents = str_replace('id="','id="' . $id, $file_contents);
        $file_contents = str_replace('url(#','url(#' . $id, $file_contents);
        $file_contents = str_replace('xlink:href="#','xlink:href="#' . $id, $file_contents);
        echo $file_contents;
    }
Related