Styling the same SVG <object> different ways

前端 未结 4 1277
抹茶落季
抹茶落季 2021-01-05 06:05

I want to have a series of the same SVG file on a page with different colours. I\'m aware that the best method of getting the SVG into the page without bloating the code, an

相关标签:
4条回答
  • 2021-01-05 06:43

    As CBroe says, its an issue with styling an external object. You can access it via JS and change it, but I doubt thats ideal and there's issues of making sure its loaded first etc.

    However, I'm not convinced this is necessarily the best method as you say, unless there are some other requirements (eg no javascript, or libs and it must be external, you can still load it via Snap load method for example then though if you support js).

    You can simply use a defs/use statement. I've just used a circle for brevity, but you could have a more complex path or whatever in there.

    jsfiddle

    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400">
      <defs>
        <style>
          .svg-circle {
            fill-rule: evenodd;
            fill: 'red';
          }
        </style>
        <circle id="myDefsCircle" class="svg-circle" r="20" cx="100" cy="100"/>
      </defs>
    
       <use x="10" y="0"   xlink:href="#myDefsCircle" style="fill:red"/>
       <use x="10" y="50"  xlink:href="#myDefsCircle" style="fill:blue"/>
       <use x="10" y="100" xlink:href="#myDefsCircle" style="fill:green"/>
    </svg>
    
    0 讨论(0)
  • 2021-01-05 06:44

    See https://css-tricks.com/using-svg/, section “Using SVG as an <object>”:

    […] if you want the CSS stuff to work, you can't use an external stylesheet or <style> on the document, you need to use a <style> element inside the SVG file itself.

    So it seems that it is not possible to style SVG elements inside an object from “outside” the object via CSS.

    0 讨论(0)
  • 2021-01-05 06:45

    I was in the same predicament, but realized it's simply not possible per the current spec because SVG documents exist in their own DOM separate from the main document, similar to iframes (see this answer). However, that doesn't mean we can't hack our way around this limitation for the time being.

    Since SVG files are plain text files, I figured why not just render it using JavaScript (being that the question did not explicitly state that JS cannot be used). Using the SVG circle above as an example, the function would look like this:

    // Render an SVG circle
    // optional oStyles = { selector: style [, ...] }
    function renderCircle(oStyles) {
      var sId = ('svg-'+performance.now()).replace('.', ''),
        sCss = '',
        sSel;
      if (!oStyles) oStyles = {};
      for (var i in oStyles) {
        // Handle group of selectors
        sSel = '';
        i.split(/ *, */).forEach(function(s) {
          sSel += '#' + sId + ' ' + s + ',';
        });
        sSel = sSel.slice(0, -1);
        sCss += sSel + '{' + oStyles[i] + '}';
      }
      return '' +
        '<svg xmlns="http://www.w3.org/2000/svg" id="' + sId + '" width="40" height="40" viewBox="0 0 40 40">' +
          '<style type="text/css">' +
          '<![CDATA[' +
          // Default styles
          '#' + sId + ' .svg-circle { fill: red; }' +
          // Overrides
          sCss +
          ']]>' +
          '</style>' +
          '<circle class="svg-circle" r="20" cx="20" cy="20"/>' +
        '</svg>';
    }
    
    document.getElementById('canvas').innerHTML = renderCircle();
    document.getElementById('canvas').innerHTML += renderCircle({'.svg-circle':'fill:blue'});
    <div id="canvas"></div>

    This works okay for a one-off image like a logo, but if you have a bunch of SVG icons, then you should consider using an SVG icon font or SVG sprites. Here's a good guide for implementing SVGs for the web in general:

    https://svgontheweb.com/

    0 讨论(0)
  • 2021-01-05 07:04
    
    document.addEventListener("DOMContentLoaded", function() {
      //attribute name
      const ATTR_NAME = "data-src";
      //base64 encoded brocken image icon
      const ERROR_PLACEHOLDER =
        "<img src='data:image/gif;base64,R0lGODlhEQATAPcAAFKyOVGxOlOxPFSyPFSzPFSyPVSyPlWyPlWyP16kTViyRFmzRVm0RV+1T2GlUGKmUWG2U2K0VGO2V2e6UmW3Wm27X3C/XWyrYHKsaXW7ZHqwbHe7dnTAYnfBcH3EcISGhIWGhIWGhYeFh4aGhoeGh4aIhY6NjpORlJOSlJSSlJSSlZWTlZiYl5qYmpuZm5ubnp6cn5+dn4SqgIqqi56eoaGfoaGhoaKho6Kio6Oio6OhpKKipKShpKSjpKSipaSjpaajpqSlqqilqKmoqaysrL+/v4TEhY/DnpLEpJTEp5vLqaXGsaDJta3FvaXKvafKv7zhs8HjuMHjucfmv8bnv6jLwrDNz7zbyrXP17bO27jP3b3V373R5MfHyMnIycrJy8rKys3MzcTL38LP3MfO3cvR3tTW09DQ1NXV19TU2dDU39jY2dra29nd2N3d397e38rlx9jr2sfQ4cjQ4czT4crT58/X58HT6cLT6sTU6MPR7cPT7MPT7cTT78vV6dba49Tc7MXT8MXT8cbU8cbU8sfU8sbV8sfV8sfU88jW8snX88rY88vY88zZ8svY9MzZ9Mza9M3a9c3b9c7b9c3b9s7b9s/c9tDc8tPe9dPf9tDd+NHe+NPf+NLf+dvg6tvi8dXh+Nbi+Nbi+dfi+djj+drk+eDg4OHg4OHh5+Xl5uLi6Orq6uzs7OTn8eXp8ers9OHq++Tr+uXs+Obs++ft++fu++Tr/OTs/OXs/Ofu/enu+eju++jv++jv/enw/O3y/fT09Pb79PP3//r6+vr6+/v9+/r7/Pn7/vv8/vz8/Pz8/f3//P7//fz9/v79//3+//7+//7//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAARABMAAAj+AGsAEUKwIEEeLdwQk8YwxxlVqCJKVJXGBZE3yhr+6YULly1bt3Dl8gTDS5c1GXHQIcVpVC1epVraobHKFBg2xnDI6cQp1jNpu0BtqvMizKkiQ9DoFDUrGkNptDT5CaLjh48YKXT6Ooasa7NYjy59auXqVZoVOkFlWrt2kiNLoUqVgqVmxQ45lQwZOsT3UCJFixgx4kTmxF1KgxIPIsRY8SBJgL7clZSYECI+d/YUIjRIEKZf0u5GGtSHixUnTJ5gwROokSyGdyHp0ZIkggIGDTZUyaMLWjJgsbMggYBgQIEDCyrEcSYtVQ8cc7YckXCggAEDAiZMCSZNWBkUN8ZKKKEw4LqBABakFJMG54oYFTaWdABAoH4ADlCkLaPiwUgTFCzIcIEDBD6QQRTSDNOGBglgMIMJIowQwgcUlmAGM9KwksKEIZAgQkAAOw==' >";
      let target = document.querySelectorAll(`[${ATTR_NAME}]`);
      //unsorted list
      let _filesList = [];
      target.forEach(function(item) {
        _filesList.push(item.getAttribute(ATTR_NAME).replace(/\\/g, "/"));
      });
      //sorted list
      let filesList = _filesList.filter(function(item, pos) {
        return _filesList.indexOf(item) == pos;
      });
      //ajax request
      filesList.forEach(function(item) {
        let ajax = new XMLHttpRequest();
        ajax.open("GET", item, true);
    
        ajax.onload = function() {
          document.querySelectorAll(`[${ATTR_NAME}="${item}"]`).forEach(item => {
            if (this.status >= 200 && this.status < 400) {
              // Success!
              item.innerHTML = this.response;
            } else {
              // Error!
              item.innerHTML = ERROR_PLACEHOLDER;
            }
          });
        };
    
        ajax.send();
      });
    });
    
    <div class="icon" data-src="icon.svg">
    
    .icon path{
      fill:#000;
    }
    
    0 讨论(0)
提交回复
热议问题