Рендеринг svg-контейнера с defs внутри

Инлайновые 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.

https://www.w3.org/TR/SVG/struct.html#Overview

Поэтому мы вынуждены скрывать 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> — это картинка, надо ее показать в любом случае! Такого, чтобы в определенных условиях не рендерить ее, еще не изобретено.»

Удивительно, что такая большая и подробная спецификация осталась непроработанной в этом аспекте.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *