web-dev-qa-db-fra.com

Comment référencer un fichier svg externe en svg correctement?

Bonjour, je travaille sur une carte svg/js, composée de nombreux petits graphiques svg (quartiers). J'ai mis chaque graphique dans un fichier propre de sorte que mon fichier svg principal puisse toujours être maintenu et non gonflé.

Comment référencer correctement un fichier svg externe depuis un autre svg?

Résultat attendu: Ouvrez 1.svg dans un navigateur et voyez un rectangle bleu. Comment cela devrait-il fonctionner: w3c: use element

Alors voici ce que j'ai essayé: 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>

un autre.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; }

Résultat:

  • Firefox: Un rectangle bleu (exactement ce que je voulais)
  • Chrome: Rien
  • Opera: Noir rectangle

Remarque: je l’ai essayé avec l’élément d’image, mais cela n’a pas fonctionné avec les feuilles de style, c’est-à-dire un rectangle noir et non bleu.

Important: Lorsque vous souhaitez référencer un autre fichier SVG et souhaitez que le fichier SVG référencé fasse partie de la structure du document, vous pouvez utiliser AJAX pour faire ça.

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

19
taffer

Cela répond à la question initiale, mais tente également de répondre à la question de référencer des fichiers SVG externes en SVG en termes plus généraux.

Manque de support SVG

Six ans plus tard, Chrome et Safari ne permettent toujours pas le référencement/le chargement de fichiers SVG externes .

C'est pourquoi <use xlink:href="another.svg#rectangle" class="blue"/> fonctionne dans Firefox, mais pas dans les navigateurs WebKit.

Tout en un fichier

Si le projet le permet, placez simplement tous les fichiers SVG dans un fichier HTML ou SVG parent. De cette façon, cela fonctionnera dans les trois navigateurs:

Mais alors, ce n'est pas vraiment externe, d'accord!

Pour tirer profit de la mise en cache et éviter de se répéter, nous souhaitons conserver le contenu SVG pouvant être répété dans un fichier externe.

Contourner le problème: insérer le fichier SVG externe via JavaScript

Conservez les styles et les définitions dans un fichier SVG, conservez la géométrie SVG dans un autre fichier et chargez simplement le premier à partir du dernier via JavaScript.

En SVG pur et en JavaScript pur

Définir ce que nous aimerions pouvoir utiliser. 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>

Utilisez la géométrie créée ci-dessus et chargez sa définition. 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>

Cela répond à l'OP.

En HTML

Même approche de base qu'en SVG pur:

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

Vous pouvez bien sûr utiliser jQuery (ou pourquoi pas l'excellent D3.js ) pour charger le fichier à la place.

Remarques

  • Attention à l'utilisation de <defs>. Je pense que c'est la bonne chose d'avoir un SVG externe, vous pouvez tout garder ordonné et organisé. (Et sans cela, nous afficherions le contenu deux fois.)
  • Je me suis débarrassé de style.css et ai simplement placé le CSS à l'intérieur du fichier styles-and-defs.
  • Si, dans la version HTML, vous observez un écart entre le SVG parent et les bordures de la fenêtre, c'est que le SVG "invisible" (avec les styles et la définition), comme tout autre SVG, est un élément inline. Pour vous débarrasser de cet espace, définissez simplement style="display: block;" sur ce SVG.
  • Téléchargez tous les exemples ici .

SVG est excellent, mais peut sembler trop peu pris en charge, bien qu'il permette de grandes choses. J'espère que cela aidera certaines personnes dans le monde.

Testé sur OS X 10.12.6 sous:

  • Firefox 59.0.2
  • Chrome 66.0.3359.139
  • Safari 11.0.1
8

De la définition dans la spécification SVG que vous êtes liés à

Les sélecteurs CSS2 ne peuvent pas être appliqués à l'arborescence DOM (conceptuellement) clonée Car son contenu ne fait pas partie de la structure formelle du document.

Cela signifie que votre sélecteur dans 1.svg ne s'applique pas à l'arborescence DOM clonée.

Alors, pourquoi ne pas simplement référencer la feuille de style d'un autre.svg à la place? Cela devrait fonctionner dans tous les navigateurs, et avec <use> et <image>.

Une autre option consiste à styler l'élément <use> dans le document svg principal (1.svg), car le style est également redirigé vers l'arbre cloné.

9
Erik Dahlström

Essayez de le faire de cette façon:

La place:

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

Utilise le:

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

L'élément <svg> n'a pas d'attribut xlink:href. Si vous devez inclure une image externe, utilisez l'élément <image>.

0
Spadar Shut