Инлайновые svg-объекты, объявленные внутри элемента <defs>
, считаются одним из эффективных способов переиспользования векторной графики. Например, можно объявить несколько иконок:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="icon1" viewBox="0 0 10 10" fill="none">
<path ... />
</symbol>
<symbol id="icon2" viewBox="0 0 10 10" fill="none">
<path ... />
</symbol>
</defs>
</svg>
Затем многократно использовать их в коде:
<svg class="my-icon"><use href="#icon1" /></svg>
Все прекрасно, только корневой элемент <svg>
(пустой) будет отрендерен браузером в размере по умолчанию, то есть 300×150 px. Кстати, в спецификации рекомендуется объявлять элементы по возможности раньше. Таким образом, если поставить их в начало документа, мы получим пустое место прямо вверху:
It is recommended that, where possible, referenced elements be defined prior to the elements that use them, in document order. Collecting all referenced elements inside of a single ‘defs’ element near the top of the file can make the markup easier to read and understand.
Поэтому мы вынуждены скрывать svg-контейнер с помощью width="0" height="0"
или style="display: none;"
:
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
...
</svg>
И кстати, скрытие через display: none;
не всегда проходит безболезненно — судя по Stack Overflow, это может вызвать проблемы с pattern
.
Примечательно, что в примерах мы обычно видим, что элементы объявляются и тут же используются (а не позже), что избавляет авторов от необходимости объяснять, почему в ином случае <svg>
приходится скрывать. Например, статья про <defs> на MDN начинается с того, что «The <defs> element is used to store graphical objects that will be used at a later time», но все это «later time» случается в пределах этого же контейнера:
<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
<!-- Some graphical objects to use -->
<defs>
<circle id="myCircle" cx="0" cy="0" r="5" />
<linearGradient id="myGradient" gradientTransform="rotate(90)">
<stop offset="20%" stop-color="gold" />
<stop offset="90%" stop-color="red" />
</linearGradient>
</defs>
<!-- using my graphical objects -->
<use x="5" y="5" href="#myCircle" fill="url('#myGradient')" />
</svg>
Там же, в статье про <use>:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<circle id="myCircle" cx="5" cy="5" r="4" stroke="blue" />
<use href="#myCircle" x="10" fill="blue" />
<use href="#myCircle" x="20" fill="white" stroke="red" />
</svg>
Выглядит так, что в итоге все заботы переданы разработчикам браузеров и веб-разработчикам. Можно в какой-то степени понять логику, почему рендерится пустой <svg>
: «Ну ладно, ты здесь пишешь какие-то определения, дело твое, но ведь <svg>
— это картинка, надо ее показать в любом случае! Такого, чтобы в определенных условиях не рендерить ее, еще не изобретено.»
Удивительно, что такая большая и подробная спецификация осталась непроработанной в этом аспекте.