xml 如何在 svg 中正确引用外部 svg 文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7215009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 14:54:33  来源:igfitidea点击:

How to reference external svg file in svg correctly?

xmlsvgreferenceelement

提问by taffer

Hello I am working on an svg/js map, which consists of many little svg graphics (City districts). I put every graphic into an own file so that my main svg file will still be maintainable and not bloated.

你好,我正在制作一个 svg/js 地图,它由许多小的 svg 图形(城市地区)组成。我将每个图形放入一个自己的文件中,这样我的主 svg 文件仍然可以维护并且不会膨胀。

How can I reference an external svg file from another svg correctly?

如何从另一个 svg 正确引用外部 svg 文件?

Expected result: Open 1.svg in a browser and see a blue rectangle. How it should work: w3c: use element

预期结果:在浏览器中打开 1.svg 并看到一个蓝色矩形。它应该如何工作:w3c:使用元素

So this is what I tried: 1.svg:

所以这就是我尝试过的:1.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet href="style.css" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-       20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
<use xlink:href="another.svg#rectangle"/>
</svg>

another.svg:

另一个.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-       20010904/DTD/svg10.dtd">
<svg id="rectangle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
<rect class="blue" x="558.5" y="570" width="5" height="5" />
</svg>

style.css

样式文件

.blue { fill: blue; }

Result:

结果:

  • Firefox: A blue rectangle (exactly what I wanted)
  • Chrome: Nothing
  • Opera: Blackrectangle
  • Firefox:一个蓝色矩形(正是我想要的)
  • 铬:没有
  • 歌剧:黑色矩形

Note: I tried it with the image element but that didn't work with the stylesheets i.e. I got a black rectangle not a blue one.

注意:我用 image 元素尝试过,但对样式表不起作用,即我得到了一个黑色矩形而不是蓝色矩形。

Important:When you want to reference another SVG andwant to have the referenced SVG to be part of the formal document structure, you can use AJAXto do that.

重要提示:当您想要引用另一个 SVG希望引用的 SVG 成为正式文档结构的一部分时,您可以使用 AJAX来做到这一点。

https://bugs.webkit.org/show_bug.cgi?id=12499

https://bugs.webkit.org/show_bug.cgi?id=12499

采纳答案by Fabien Snauwaert

This answers the original question, but attempts to answer the matter of referencing external SVG files in SVG in broader terms, too.

这回答了最初的问题,但也试图从更广泛的角度回答在 SVG 中引用外部 SVG 文件的问题。

Lack of SVG support

缺乏 SVG 支持

Six years later, Chrome and Safari still do not allow for the referencing/loading of external SVG files.

六年后,Chrome 和 Safari 仍然不允许引用/加载外部 SVG 文件

This is why <use xlink:href="another.svg#rectangle" class="blue"/>works in Firefox, but not in WebKit browsers.

这就是为什么<use xlink:href="another.svg#rectangle" class="blue"/>在 Firefox 中有效,但在 WebKit 浏览器中无效的原因。

All in one file

全部在一个文件中

If the project can afford it, simply put all of the SVG files in one parent HTML or SVG file. This way, it'll work in all three browsers:

如果项目负担得起,只需将所有 SVG 文件放在一个父 HTML 或 SVG 文件中。这样,它将在所有三个浏览器中工作:

But then, it's not really external, granted!

但是,这并不是真正的外部,当然!

To benefit from caching and avoid repeating oneself, we'd like to keep repeatable SVG content in an external file.

为了从缓存中受益并避免重复,我们希望在外部文件中保留可重复的 SVG 内容。

Work around: insert the external SVG file via JavaScript

解决方法:通过 JavaScript 插入外部 SVG 文件

Keep the styles and definitions in one SVG file, keep the SVG geometry in some other file, and simply load the former from the latter via JavaScript.

将样式和定义保存在一个 SVG 文件中,将 SVG 几何图形保存在其他文件中,然后通过 JavaScript 从后者加载前者。

In pure SVG and pure JavaScript

在纯 SVG 和纯 JavaScript 中

Define what we'd like to be able to use. styles-and-defs.svg:

定义我们希望能够使用的内容。styles-and-defs.svg

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <style type="text/css" >
    <![CDATA[

    .blue { fill: blue; }

    ]]>
    </style>

    <defs>
        <rect id="rectangle" class="blue" width="50" height="50" />
    </defs>
</svg>

Use the geometry created above, and load its definition. parent.svg:

使用上面创建的几何图形,并加载其定义。parent.svg

<svg version="1.1"
    baseProfile="full"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    width="420" height="120">

    <use xlink:href="#rectangle" x="10" y="10" />

    <script><![CDATA[

        /** When the document is ready, this self-executing function will be run. **/
        (function() {

            var ajax = new XMLHttpRequest();
            ajax.open("GET", "styles-and-defs.svg", true);
            ajax.send();

            /**
             * Append the external SVG to this very SVG.
             *
             * Notice the use of an SVG selector on the document derived from the AJAX result.
             *  This is because the full document cannot be included directly into the SVG.
             *  Trying to include to do so would result in:
             *      `HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy` in Firefox;
             *      `Nodes of type '#document' may not be inserted inside nodes of type 'svg'.` in Chrome.
             */
            ajax.onload = function(e) {
                var parser = new DOMParser();
                var ajaxdoc = parser.parseFromString( ajax.responseText, "image/svg+xml" );
                document.getElementsByTagName('svg')[0].appendChild( ajaxdoc.getElementsByTagName('svg')[0] );
            }

        })();   /* END (anonymous function) */

    ]]></script>
</svg>

This answers the OP.

这回答了OP。

In HTML

在 HTML 中

Same basic approach as in pure SVG:

与纯 SVG 相同的基本方法:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        Load external SVG (HTML)
    </title>
    <meta name="author" content="Fabien Snauwaert">
</head>

<body>

    <svg version="1.1"
    baseProfile="full"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    width="420" height="120">
        <use xlink:href="#rectangle" x="10" y="10"  />
    </svg>

<script>

    /** When the document is ready, this self-executing function will be run. **/
    (function() {

        var ajax = new XMLHttpRequest();
        ajax.open("GET", "styles-and-defs.svg", true);
        ajax.send();

        /**
         * Append the external SVG to this very SVG.
         *
         * Notice the use of an SVG selector on the document derived from the AJAX result.
         *  This is because the full cannot be included directly into the SVG.
         *  Trying to include to do so would result in:
         *      `HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy` in Firefox;
         *      `Nodes of type '#document' may not be inserted inside nodes of type 'svg'.` in Chrome.
         */
        ajax.onload = function(e) {
            var parser = new DOMParser();
            var ajaxdoc = parser.parseFromString( ajax.responseText, "image/svg+xml" );
            document.getElementsByTagName('body')[0].appendChild( ajaxdoc.getElementsByTagName('svg')[0] );
        }

    })();   /* END (anonymous function) */

</script>

</body>
</html>

You could of course use jQuery (or why not the excellent D3.js) to load the file instead.

您当然可以使用 jQuery(或者为什么不使用优秀的D3.js)来加载文件。

Remarks

评论

  • Mind the use of <defs>. I believe this is the nice thing about having an external SVG, you can keep everything neat and organized. (And without it, we'd be displaying the content twice.)
  • I got rid of style.cssand simply put the CSS inside of the styles-and-defs file.
  • If, in the HTML version, you observe a gap between the parent SVG and the window borders, this is because the "invisible" SVG (with the styles and definition), like any other SVG, is an inlineelement. To get rid of this gap, simply set style="display: block;"on that SVG.
  • Download all examples here.
  • 注意使用<defs>. 我相信这是拥有外部 SVG 的好处,您可以保持一切整洁有序。(如果没有它,我们将显示两次内容。)
  • 我摆脱了style.css并简单地将 CSS 放在了 style-and-defs 文件中。
  • 如果在 HTML 版本中,您观察到父 SVG 和窗口边框之间存在间隙,这是因为“不可见”的 SVG(具有样式和定义)与任何其他 SVG 一样,也是一个inline元素。要消除这种差距,只需style="display: block;"在该 SVG 上设置即可。
  • 在此处下载所有示例


SVG is great but can appear to be too little supported, while it does allow for some great things. I hope this helps some folks out there.

SVG 很棒,但似乎支持得太少,但它确实允许一些很棒的东西。我希望这可以帮助那里的一些人。

Tested OK on OS X 10.12.6 in:

在 OS X 10.12.6 上测试正常:

  • Firefox 59.0.2
  • Chrome 66.0.3359.139
  • Safari 11.0.1
  • 火狐 59.0.2
  • 铬 66.0.3359.139
  • Safari 11.0.1

回答by Erik Dahlstr?m

From the definition in the SVG spec that you linked to:

根据您链接到的 SVG 规范中的定义:

CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree because its contents are not part of the formal document structure.

CSS2 选择器不能应用于(概念上)克隆的 DOM 树,因为它的内容不是正式文档结构的一部分。

That means that your selector in 1.svg doesn't apply to the cloned DOM tree.

这意味着 1.svg 中的选择器不适用于克隆的 DOM 树。

So why not simply reference the stylesheet from another.svg instead? That should work in all browsers, and with both <use>and <image>.

那么为什么不简单地从 another.svg 引用样式表呢?这应该适用于所有浏览器,并且适用于<use><image>

Another option is to style the <use>element in the main svg document (1.svg), since style is cascaded down to the cloned tree from there too.

另一种选择是<use>在主 svg 文档 (1.svg) 中设置元素的样式,因为样式也从那里向下级联到克隆树。

回答by Spadar Shut

Try to do it this way:

尝试这样做:

The square:

广场:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
    <rect x="558.5" y="570" width="5" height="5" id="rectangle" />
</svg>

Use it:

用它:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet href="style.css" type="text/css"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
    <use xlink:href="another.svg#rectangle" class="blue"/>
</svg>

回答by Spadar Shut

<svg>element doesn't have xlink:hrefattribute, if you need to include an external image use the <image>element.

<svg>元素没有xlink:href属性,如果您需要包含外部图像,请使用该<image>元素。