Порядок слоёв и z-index в SVG

Порядок отрисовки элементов в SVG определяется не свойством z-index в привычном смысле из CSS, а моделью “painting order” — последовательностью, в которой узлы описаны в дереве документа. Каждый последующий элемент визуально перекрывает предыдущий, если они пересекаются и находятся в одном и том же контексте наложения.

SVG не использует полноценный z-index для большинства графических элементов. Вместо этого действует строгое правило:

  • элементы, расположенные ниже в DOM, отрисовываются поверх элементов, расположенных выше;
  • порядок групп (<g>) влияет на целый набор дочерних элементов;
  • вложенность групп создаёт локальные контексты отрисовки.

Это означает, что изменение визуального слоя чаще всего достигается не стилями, а перестановкой элементов в дереве.

Пример логики отрисовки:

<svg>
  <rect x="0" y="0" width="100" height="100" fill="red" />
  <rect x="30" y="30" width="100" height="100" fill="blue" />
</svg>

Синий прямоугольник будет поверх красного, потому что он объявлен позже.

Ограничения CSS z-index в SVG

Свойство z-index работает только в ограниченных сценариях:

  • SVG-элемент должен быть частью CSS stacking context;
  • элемент должен иметь позиционирование или участвовать в compositing context;
  • часто требуется position, opacity < 1, transform или isolation.

Даже в этих случаях поведение отличается от HTML:

  • z-index влияет на контейнер, а не на отдельные SVG primitive элементы;
  • внутри одного <svg> порядок DOM всё ещё доминирует.

Таким образом, попытка управлять слоями через CSS в SVG часто приводит к непредсказуемому результату.

Контексты наложения и группы <g>

Группы <g> являются ключевым инструментом управления слоями.

Каждая группа:

  • объединяет набор элементов в единый слой;
  • участвует в порядке отрисовки как единый блок;
  • может иметь трансформации и стили, влияющие на дочерние элементы.
<svg>
  <g id="background">
    <rect width="400" height="200" fill="#eee" />
  </g>

  <g id="foreground">
    <circle cx="100" cy="100" r="40" fill="black" />
  </g>
</svg>

Группа foreground всегда будет поверх background, если расположена ниже в DOM.

Перекрытие слоёв в сложных SVG-сценариях

В сложных графиках возникают ситуации, когда визуальная логика требует независимого управления слоями:

  • оси должны быть поверх сетки;
  • точки должны быть поверх линий;
  • tooltip должен быть поверх всего;
  • легенда может быть отдельно от графического слоя.

SVG не предоставляет встроенной системы слоёв, поэтому используется комбинация:

  • перестановки DOM;
  • группировки;
  • изоляции контекстов;
  • отдельные <svg> внутри одного контейнера.

Модель отрисовки в Nivo

Библиотека Nivo строит графики на SVG (или Canvas в отдельных режимах), и управление слоями является частью её архитектуры.

В Nivo слойность определяется не CSS, а структурой render pipeline.

Типичная схема слоёв в графиках:

  1. фон (background)
  2. сетка (grid)
  3. оси (axes)
  4. данные (bars, lines, points)
  5. вспомогательные элементы (markers, annotations)
  6. интерактивные элементы (crosshair, hover layers)
  7. tooltip (вне SVG или поверх через портал)

Каждый из этих уровней реализуется как отдельная группа или отдельный render layer.

Принцип layers в Nivo

Во многих компонентах Nivo используется проп layers, который задаёт порядок отрисовки:

  • массив функций или строковых идентификаторов слоёв;
  • порядок массива = порядок DOM;
  • последний слой всегда выше визуально.

Пример логики:

layers={[
  'grid',
  'axes',
  'bars',
  'markers',
  'legends'
]}

Изменение порядка мгновенно влияет на визуальную иерархию без изменения внутренних компонентов.

Почему порядок критичен для графиков

Визуализация данных требует строгого разделения уровней:

  • сетка должна быть слабозаметной и всегда под данными;
  • линии и бары должны быть читаемыми без перекрытия осей;
  • интерактивные элементы должны иметь приоритет над статикой.

Если нарушить порядок:

  • оси могут перекрыть данные;
  • tooltip может оказаться под графиком;
  • hover-индикаторы станут неразличимыми.

SVG не исправляет эти конфликты автоматически, поэтому ответственность лежит на структуре слоёв.

Группы, клиппинг и порядок отрисовки

Дополнительный уровень сложности создают:

  • clipPath
  • mask
  • defs
  • use

Эти элементы влияют не только на видимость, но и на порядок композиции.

Например, clipPath применяется до финального отображения, но не участвует в визуальном stacking order. Это часто вызывает путаницу: элемент может быть “поверх”, но визуально обрезан.

Перекрытие интерактивных слоёв

В Nivo интерактивность часто реализуется через:

  • прозрачные overlay-группы;
  • невидимые hit-area элементы;
  • отдельные слои для событий мыши.

Такие слои почти всегда должны находиться последними в DOM.

Пример логики:

  • данные отрисованы;
  • поверх них добавляется прозрачный слой для onMouseMove;
  • tooltip рендерится отдельно через portal.

Порталы и выход за пределы SVG

Tooltip и модальные подсказки часто не находятся внутри SVG вообще.

Причины:

  • SVG ограничен по управлению overflow и z-order;
  • HTML overlay проще позиционировать;
  • DOM outside SVG позволяет использовать полноценный z-index.

Это создаёт гибридную модель:

  • SVG отвечает за графику;
  • HTML — за интерактивные всплывающие элементы.

Изоляция контекста через isolation

CSS свойство isolation: isolate создаёт новый stacking context, что иногда используется для контроля наложения SVG внутри HTML контейнеров.

Это полезно в случаях:

  • несколько графиков на странице;
  • перекрывающиеся SVG-контейнеры;
  • сложные dashboard-композиции.

Однако внутри самого SVG это не заменяет DOM-порядок.

Transform и влияние на слой

Любое применение transform:

  • создаёт новый compositing context;
  • может изменить поведение наложения;
  • влияет на рендеринг GPU.

В SVG это особенно важно, потому что:

  • трансформированные группы часто “выпадают” из общего порядка;
  • производительность и визуальное поведение становятся зависимыми от структуры групп.

Частые ошибки при работе со слоями

Нарушения логики stacking order обычно возникают из-за:

  • попытки управлять слоями через z-index на SVG-элементах;
  • отсутствия группировки логически связанных элементов;
  • смешивания интерактивных и статичных слоёв в одной группе;
  • неправильного порядка layers в Nivo;
  • использования append вместо контролируемой вставки в DOM.

Переопределение порядка через React (в контексте Nivo)

Поскольку Nivo построен на React, порядок элементов часто определяется:

  • порядком JSX-компонентов;
  • порядком вызова render функций;
  • массивами слоёв, возвращающих SVG группы.

React reconciliation напрямую влияет на итоговый DOM SVG, а значит и на визуальный stacking order.

Логическая модель слоёв в визуализации

Устойчивый подход к проектированию SVG-графиков:

  • разделение данных и декораций;
  • фиксированный порядок базовых слоёв;
  • отдельные слои для интерактивности;
  • изоляция tooltip и overlay-элементов;
  • минимизация пересечений внутри одного слоя.

Такая структура снижает зависимость от случайного DOM-порядка и делает визуализацию предсказуемой.

Поведение при пересечении прозрачных элементов

Даже если элемент визуально прозрачен:

  • он всё равно участвует в stacking order;
  • может перекрывать события мыши;
  • влияет на hit-testing.

Это особенно важно для Nivo charts, где прозрачные области часто используются для hover-зон.

SVG и отсутствие полноценного z-index как архитектурное ограничение

Отсутствие классического z-index приводит к тому, что:

  • порядок становится частью данных, а не стилей;
  • визуальная логика тесно связана с структурой документа;
  • управление слоями требует явного проектирования, а не декларативных правил CSS.

В результате SVG-графики, включая Nivo, опираются на структурную композицию, а не на каскадные правила наложения.