Change attributes defined in defs on use element

前端 未结 3 569
旧时难觅i
旧时难觅i 2021-02-02 09:56

How can I achieve changing the style of an \"use element\", defined in defs, through scripting? I was trying to move in the w3c working draft interfaces, but I lost in that laby

相关标签:
3条回答
  • 2021-02-02 10:39

    As you can see in my test page, if you define the visual style of an element inside the <defs> section of a document you cannot override that style on the <use> instance, not through a visual attribute, style attribute, or CSS class applied to the <use>.

    Snapshot of test results from linked SVG file, showing that only unstyled elements can be overridden

    Further, you cannot use a visual attribute on the <use> element to cascade styles down to elements of the source; you must use CSS styling for this.

    You'll have to:

    1. Ensure that your defined elements have no visual style applied, and
    2. Use either CSS or set a manually-parsed-or-created style attribute, e.g.

      node.setAttribute('style','fill:blue');
      

    As noted here you can use either setAttribute(...) or setAttributeNS(null,...) for SVG attributes.

    Update: To answer your second question:

    What if the referenced element is a "g" which contains 2 other elements, like a rect and a text?

    You cannot use CSS rules to select the pseudo-children of a <use>; they simply don't exist. What you can do, however, is apply the unchanging styling that you want to preserve inside the <def> and then apply the style you want on the <use>.

    For example:

    <defs>
      <g id="foo">
        <!-- Every rect instance should be filled with blue -->
        <rect width="54" height="58" x="1.5" y="1.5"
              fill="blue" />
        <!-- I want to be able to change text color per use
             so I must be sure not to specify the fill style -->
        <text x="-34" y="47" transform="matrix(0.668,-0.744,0.744,0.668,0,0)"
         style="font-size:30px;stroke-width:0px">JC!</text>
      </g>
    </defs>
    <use xlink:href="#foo" style="fill:orange" transform="translate(0,-100)" />
    <use xlink:href="#foo" style="fill:yellow" transform="translate(0, 100)" />
    

    This only works if you want all changeable items to have their attributes set the same way.

    Unlike HTML, the markup in SVG is the presentation. What I've suggested above is a bit of a hack that happens to work, but in general <use> elements are designed to instantiate the full appearance of a definition. If you need custom appearance per instance, perhaps you should consider cloning elements, modifying properties, and adding those to the document instead of hacking a <use>.

    0 讨论(0)
  • 2021-02-02 10:40

    Nowadays, thanks to CSS variables and some clever <div> nesting, it can be done.
    Check out my CodePen here

    The trick is to contain your SVG in a div and set the style variables in a nested <style> tag:

    <div class="svg-container">
      <svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
        <style>
          div.svg-container {
            --stroke: red;
            --fill: blue;
          }
        </style>
        <circle id="myCircle" cx="5" cy="5" r="4" style="stroke:var(--stroke);fill:var(--fill);"/>
      </svg>
    </div>
    
    <div class="svg-container circle-1">
      <svg viewBox="0 0 30 10"  xmlns="http://www.w3.org/2000/svg">  
        <use href="#myCircle" x="10"/>
      </svg>
    </div>
    

    Notice that the style rule here points to the div.class?
    Now in you CSS file you can make a more specific rule pointing to the <svg> within the container:

    .circle-1 svg {
      --stroke: yellow;
      --fill: salmon;
    }
    

    Note: I did experiment to get this working, it was tricky ;-)

    0 讨论(0)
  • 2021-02-02 10:48

    To add to @Phrogz answer, It looks like even if i try to overwrite the styles defined inside the symbol tag its not getting overwritten in the use tag. A fiddle for that http://jsfiddle.net/rajkamal/xrdgf/

    0 讨论(0)
提交回复
热议问题