Как правильно ссылаться на внешний файл SVG в SVG?
Здравствуйте, я работаю над картой svg/js, которая состоит из множества маленьких графиков svg (Городские районы). Я помещаю каждую графику в отдельный файл, чтобы мой основной файл 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: синий прямоугольник (именно то, что я хотел)
- Хром: ничего
- Опера: черный прямоугольник
Примечание: я попробовал это с элементом изображения, но это не сработало с таблицами стилей, т.е. я получил черный прямоугольник, а не синий.
Важное замечание: Если вы хотите сослаться на другой SVG и хотите, чтобы ссылочный SVG был частью формальной структуры документа, вы можете использовать AJAX для этого.
5 ответов
Из определения в спецификации SVG, с которым вы связались:
Селекторы CSS2 нельзя применять к (концептуально) клонированному дереву DOM, поскольку его содержимое не является частью формальной структуры документа.
Это означает, что ваш селектор в 1.svg не применяется к клонированному дереву DOM.
Так почему бы просто не ссылаться на таблицу стилей из другого.svg? Это должно работать во всех браузерах, и с обоими <use>
а также <image>
,
Другим вариантом является стиль <use>
элемент в главном документе svg (1.svg), так как оттуда стиль также распространяется вниз к клонированному дереву.
Это отвечает на первоначальный вопрос, но пытается ответить на вопрос ссылки на внешние файлы SVG в SVG также в более широком смысле.
Отсутствие поддержки SVG
Шесть лет спустя, Chrome и Safari по-прежнему не допускают ссылки / загрузки внешних файлов SVG.
Вот почему <use xlink:href="another.svg#rectangle" class="blue"/>
работает в Firefox, но не в браузерах WebKit.
Все в одном файле
Если проект может себе это позволить, просто поместите все файлы SVG в один родительский файл HTML или SVG. Таким образом, он будет работать во всех трех браузерах:
Но тогда, это не действительно внешнее, предоставлено!
Чтобы извлечь выгоду из кэширования и избежать повторения, мы хотели бы сохранить воспроизводимый SVG-контент во внешнем файле.
Обходной путь: вставьте внешний файл SVG через JavaScript
Храните стили и определения в одном файле 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>
Это отвечает ОП.
В 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, вы можете держать все аккуратно и организованно. (А без этого мы бы отображали контент дважды.) - Я избавился от
style.css
и просто поместите CSS внутри файла styles-and-defs. - Если в HTML-версии вы наблюдаете разрыв между родительским SVG и границами окна, это происходит потому, что "невидимый" SVG (со стилями и определением), как и любой другой SVG, является
inline
элемент. Чтобы избавиться от этого пробела, просто установитеstyle="display: block;"
на этом SVG. - Загрузите все примеры здесь.
SVG великолепен, но может показаться слишком мало поддерживаемым, хотя он допускает некоторые замечательные вещи. Я надеюсь, что это помогает некоторым людям там.
Протестировано нормально на OS X 10.12.6 в:
- Firefox 59.0.2
- Chrome 66.0.3359.139
- Safari 11.0.1
Попробуйте сделать это так:
Площадь:
<?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>
<svg>
элемент не имеет xlink:href
атрибут, если вам нужно включить внешнее изображение, используйте <image>
элемент.
Если вы хотите сослаться на весь файл SVG, SVG 2 (при реализации в браузерах) позволит ссылаться на другой файл SVG без идентификатора фрагмента :
Новое в SVG 2:
href
без фрагмента позволяет ссылаться на весь документ SVG, не гарантируя, что он имеет идентификатор корневого элемента.
До:
<!-- my-vector.svg -->
<svg id="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle r="10" cx="12" cy="12" />
</svg>
<use href="my-vector.svg#icon"></use>
После (нет необходимости определять
id="..."
на
svg
):
<!-- my-vector.svg -->
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle r="10" cx="12" cy="12" />
</svg>
<use href="my-vector.svg"></use>
SVG 2, похоже, находится в процессе разработки в основных браузерах (см. эту функцию Chrome и, в частности, эту проблему Chromium: Issue 366545: [SVG2] Разрешить ссылаться на целые файлы ).