web-dev-qa-db-ja.com

svgで外部svgファイルを正しく参照する方法は?

こんにちは私は多くの小さなsvgグラフィック(市地区)で構成されるsvg/jsマップに取り組んでいます。すべてのグラフィックを独自のファイルに入れるので、メインのsvgファイルは引き続き保守可能で、肥大化しません。

別のsvgから外部svgファイルを正しく参照するにはどうすればよいですか?

期待される結果:1.svgをブラウザーで開くと、青い四角形が表示されます。動作方法: w3c:要素を使用

これが私が試したものです: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:

<?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; }

結果:

  • Firefox:青い長方形(まさに私が欲しかったもの)
  • Chrome:なし
  • Opera:Black長方形

注:画像要素で試しましたが、スタイルシートでは機能しませんでした。つまり、青い長方形ではなく黒い長方形が表示されました。

重要:別のSVGを参照する場合およびに正式なドキュメント構造の一部としてSVGを参照している場合、 AJAXを使用 を使用してこれを行うことができます。

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

22
taffer

これは元の質問に答えますが、SVGで外部SVGファイルを参照するという問題にも広義で回答しようとします。

SVGサポートの欠如

6年後、ChromeとSafariでは、外部SVGファイルの参照/ロードはまだ許可されていません

これが、Firefoxでは<use xlink:href="another.svg#rectangle" class="blue"/>が機能するが、WebKitブラウザーでは機能しない理由です。

1つのファイルにすべて

プロジェクトに余裕がある場合は、すべてのSVGファイルを1つの親HTMLまたはSVGファイルに配置するだけです。これにより、3つのブラウザすべてで機能します。

しかし、それは実際には外部的なものではありません。

キャッシングのメリットを活用し、自分自身の繰り返しを避けるために、繰り返し可能なSVGコンテンツを外部ファイルに保持したいと考えています。

回避策:JavaScript経由で外部SVGファイルを挿入します

スタイルと定義を1つのSVGファイルに保存し、SVGジオメトリを他のファイルに保存し、JavaScriptを介して前者を後者からロードするだけです。

純粋なSVGと純粋なJavaScript

何を使用できるようにするかを定義します。 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>

上記で作成したジオメトリを使用して、その定義をロードします。 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>

これはOPに応答します。

HTMLで

純粋な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>

もちろん、代わりにjQuery(または優れた D3.js )を使用してファイルをロードすることもできます。

備考

  • <defs>の使用に注意してください。私はこれが外部SVGを持つことのいいところだと思います。すべてをきちんと整理しておくことができます。 (それがなければ、コンテンツは2回表示されます。)
  • 私はstyle.cssを取り除き、単にCSSをstyles-and-defsファイル内に配置しました。
  • HTMLバージョンで、親SVGとウィンドウの境界線の間に隙間がある場合、これは、他のSVGと同様に、(スタイルと定義を含む)「非表示」SVGがinline要素であるためです。 。このギャップをなくすには、そのSVGにstyle="display: block;"を設定するだけです。
  • ここにすべての例をダウンロード

SVGは素晴らしいですが、サポートが少なすぎるように見えるかもしれませんが、いくつかの素晴らしいことは可能です。これが一部の人々の役に立てば幸いです。

OS X 10.12.6でテスト済みOK:

  • Firefox 59.0.2
  • Chrome 66.0.3359.139
  • Safari 11.0.1
9

リンク先 であるSVG仕様の定義から:

CSS2セレクターは、その内容が正式なドキュメント構造の一部ではないため、(概念的に)複製されたDOMツリーに適用できません。

つまり、1.svgのセレクターは、複製されたDOMツリーには適用されません。

では、代わりに別の.svgからスタイルシートを単に参照しないのはなぜですか?これは、すべてのブラウザで、<use><image>の両方で機能するはずです。

もう1つのオプションは、メインのsvgドキュメント(1.svg)の<use>要素にスタイルを設定することです。スタイルはそこから複製されたツリーにもカスケードされます。

9
Erik Dahlström

このようにしてみてください:

広場:

<?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>

これを使って:

<?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>
3
Spadar Shut

<svg>要素にはxlink:href属性がありません。外部画像を含める必要がある場合は、<image>要素を使用してください。

1
Spadar Shut