Область видимости переменных (определений, шаблонов) в SVG, включенных в HTML
В одном из ответов на SO заметил, что на страницу HTML помещены несколько тегов (файлов?) SVG. Определение шаблона пути в <symbol></symbol> было задано в первом теге, а считывалось это определение в остальных трех. Кроме того, объявление xmlns также присутствует только в первом случае.
Я попробовал заменить <symbol> на <g> - все работает по-прежнему.
Отсюда вопросы:
1. Как рассматривать несколько тегов SVG в плане области видимости определений шаблонов или групп? Можно определять шаблоны в любом теге (файле) SVG в пределах документа?
2. Почему атрибут xmlns, который требуется для открытия файла SVG, опущен в других тегах и какие существуют на этот счет правила?
3. Можно ли подключить файл SVG со всеми определениями в head, а пользоваться этими определениями в body в элементах SVG.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="0" height="0" viewBox="0 0 9.8 14.8" >
<g id="marker" >
<path d="M9.831 4.916c0 2.714-3.538 8.487-4.913 9.867C3.437 13.307 0 7.631 0 4.916S2.201 0 4.916 0s4.915 2.201 4.915 4.916z"/>
<circle cx="4.912" cy="4.916" r="2.932" fill="#E7EDEF"/>
</g>
</svg>
<svg width="19.6" height="29.6" viewBox="0 0 9.8 14.8">
<use class="u1" href="#marker" />
</svg>
<svg width="19.6" height="29.6" viewBox="0 0 9.8 14.8">
<use class="u2" href="#marker" />
</svg>
<svg width="19.6" height="29.6" viewBox="0 0 9.8 14.8">
<use class="u3" href="#marker" />
</svg>
Код взят со страницы вопроса: Не работает свойство fill для спрайта svg
Ответы (2 шт):
Как совершенно верно комментирует: @Alexey Ten
Отдельный SVG-файл должен быть валидным XML и иметь правильный namespace. SVG встроенные в HTML разбираются HTML-парсером и он ничего не знает про namespace-ы
Добавлю также, что и ошибки в написании кода SVG, HTML-парсер тоже пропускает.
И это браузерная ловушка, которая ставит, даже опытных разработчиков в тупик во время поиска причин отказа или неожидаемого результата работы приложения.
Сообщения об ошибке нет, парсер HTML просто проигнорирует первую ошибку SVG кода, выполнит команду, но не будет дальше обрабатывать другие строки SVG
А причина может быть тривиальная, - не закрыт тег одной из команд SVG.
- Это показано на примере ниже, не закрыт тег
<rect>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="400" viewBox="0 0 400 400" >
<!-- Не закрыт тег rect, нужно "/>" либо "</rect>" -->
<rect x="50" y="50" width="50%" height="50%" rx="5%" fill="purple" >
</svg>
- Во втором примере к первой ошибочной команде добавлена вторая правильная команда с закрытием тега.
Должен быть нарисованы два квадрата: пурпурный и желтый, но жёлтый квадрат из-за ошибки в первой строке не будет отображен:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="400" viewBox="0 0 400 400" >
<!-- Не закрыт тег rect, нужно "/>" либо "</rect>" -->
<rect x="50" y="50" width="50%" height="50%" rx="5%" fill="purple" >
<!-- Тег закрыт, но из-за ошибки в первой строке, эта не будет показана -->
<rect x="50" y="150" width="50" height="50 rx="5%" fill="gold" />
</svg>
Теперь сохраним эти файлы в формате SVG и запустим в браузере:
- Парсер Chrome выведет сообщение об ошибке:
- Парсер FireFox:
Вывод:
Проектируйте приложение SVG в самостоятельном файле SVG и проверять его, на мой взгляд лучше в Firefox. Так как в Chrome внедряют экспериментальные технологии, не дождавшись выхода оф. версии SVG2.
Поэтому, что может работать в Chrome, может не работать в Safari и FF
3. Можно ли подключить файл SVG со всеми определениями в head, а пользоваться этими определениями в body в элементах SVG.
Да, файл svg можно подключать к Html инлайн способом, то есть просто скопировать код SVG, как в топике, который вы указали в вопросе
Можно добавить файл с помощью <object> это делается, когда нужно подключить файлы SVG с большим объемом, например спрайты
Как ещё можно подключить SVG к HTML можно посмотреть здесь
Javascript + SVG + namespace
Пример, в котором демонстрируется важность значения указания namespace в JS при создании SVG объектов.
Кстати, это один из самых часто задаваемых вопросов в сети, почему при указании setAttribute атрибуты объектов SVG не изменяются.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="400">
<script type="text/ecmascript"><![CDATA[
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
function createCircle() {
var newCircle = document.createElementNS(svgNS,"circle");
newCircle.setAttribute(null,"cx",Math.random() * 100+250);
newCircle.setAttribute(null,"cy",Math.random() * 100+100);
newCircle.setAttribute(null,"r",Math.random() * 100);
newCircle.setAttribute(null,"stroke",Math.random() * 100);
newCircle.setAttribute(null,"fill-opacity",Math.random());
var red = Math.round(Math.random() * 255);
var green = Math.round(Math.random() * 255);
var blue = Math.round(Math.random() * 255);
newCircle.setAttributeNS(null,"fill","rgb("+ red +","+ green+","+blue+")");
document.getElementById("firstCircle").appendChild(newCircle);
}
]]></script>
<g id="firstCircle" onclick="createCircle()">
<rect x="50" y="20" width="150" height="30" rx="10" fill="yellowgreen" />
<text x="64" y="40" fill="purple" font-size="16px">Create a new circle.</text>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="400">
<script type="text/ecmascript"><![CDATA[
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
function createCircle() {
var newCircle = document.createElementNS(svgNS,"circle");
newCircle.setAttribute(null,"cx",Math.random() * 100+250);
newCircle.setAttribute(null,"cy",Math.random() * 100+100);
newCircle.setAttribute(null,"r",Math.random() * 100);
newCircle.setAttribute(null,"stroke",Math.random() * 100);
newCircle.setAttribute(null,"fill-opacity",Math.random());
var red = Math.round(Math.random() * 255);
var green = Math.round(Math.random() * 255);
var blue = Math.round(Math.random() * 255);
newCircle.setAttribute(null,"fill","rgb("+ red +","+ green+","+blue+")");
document.getElementById("firstCircle").appendChild(newCircle);
}
]]></script>
<g id="firstCircle" onclick="createCircle()">
<rect x="50" y="20" width="150" height="30" rx="10" fill="yellowgreen" />
<text x="64" y="40" fill="purple" font-size="16px">Create a new circle.</text>
</g>
</svg>
Теперь заменим setAttribute на setAttributeNS
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="400">
<script type="text/ecmascript"><![CDATA[
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
function createCircle() {
var newCircle = document.createElementNS(svgNS,"circle");
newCircle.setAttributeNS(null,"cx",Math.random() * 100+250);
newCircle.setAttributeNS(null,"cy",Math.random() * 100+100);
newCircle.setAttributeNS(null,"r",Math.random() * 100);
newCircle.setAttributeNS(null,"stroke",Math.random() * 100);
newCircle.setAttributeNS(null,"fill-opacity",Math.random());
var red = Math.round(Math.random() * 255);
var green = Math.round(Math.random() * 255);
var blue = Math.round(Math.random() * 255);
newCircle.setAttributeNS(null,"fill","rgb("+ red +","+ green+","+blue+")");
document.getElementById("firstCircle").appendChild(newCircle);
}
]]></script>
<g id="firstCircle" onclick="createCircle()">
<rect x="50" y="20" width="150" height="30" rx="10" fill="yellowgreen" />
<text x="64" y="40" fill="purple" font-size="16px">Create a new circle.</text>
</g>
</svg>

