SVG и canvas — это технологии, которые можно использовать для рисования чего-либо на веб-страницах. Поэтому их стоит сравнить и разобраться в том, когда стоит применять SVG, а когда — canvas. Даже весьма поверхностное понимание сути этих технологий позволяет сделать вполне осознанный выбор. Собственно говоря, вот — две типичных ситуации, в одной из которых стоит предпочесть SVG, а в другой — canvas:

  • Нужно нарисовать небольшую иконку? Это, безусловно, территория SVG.
  • Нужно создать интерактивную браузерную игру? Тут, определённо, нужна технология canvas.

Автор статьи, перевод которой мы сегодня публикуем, говорит, что знает о том, что пока не раскрыл причины такого выбора. Но он надеется, что эти причины станут совершенно очевидными после того, как он поделится некоторыми подробностями об SVG и canvas.

SVG — векторная графика, описываемая декларативно


Если вы знаете о том, что вам нужно разместить на веб-странице векторное изображение, это значит, что вам подходит SVG. Векторные изображения обычно выглядят лучше аналогичных растровых, хранящихся, например, в JPG-файлах. Кроме того, файлы векторных изображений обычно меньше файлов растровых изображений.

В результате оказывается, что SVG очень часто используется для рисования логотипов. Код, описывающий такие изображения, можно встроить прямо в HTML. Он выглядит как набор декларативных инструкций:

<svg viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="50" />
</svg>

Если вам нужно, чтобы изображения были бы гибкими и отзывчивыми, значит SVG — это ваш выбор.

Canvas — JavaScript-API для рисования


Для формирования canvas-изображений в HTML-коде страницы размещают элемент <canvas>, после чего, средствами JavaScript, «рисуют» на этом элементе. Другими словами, программист даёт браузеру команды, касающиеся того, как ему нужно что-то нарисовать (такой подход ближе к императивному, чем к декларативному). Вот как это выглядит:

<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');
  var centerX = canvas.width / 2;
  var centerY = canvas.height / 2;
  var radius = 70;

  context.beginPath();
  context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  context.fillStyle = 'green';
  context.fill();
</script>

SVG-изображения хранятся в DOM


Если вы знакомы с событиями DOM, наподобие click и mouseDown, то знайте о том, что этими событиями можно пользоваться и при работе с SVG. В этом плане SVG-элемент <circle> не особенно сильно отличается от HTML-элемента <div>.

<svg viewBox="0 0 100 100">
  
  <circle cx="50" cy="50" r="50" />
  
  <script>
    document.querySelector('circle').addEventListener('click', e => {
      e.target.style.fill = "red";
    });
  </script>
  
</svg>

SVG лучше подходит для обеспечения доступности содержимого страниц


Элементу canvas вполне можно назначит его текстовую альтернативу:

<canvas aria-label="Hello ARIA World" role="img"></canvas>

То же самое можно сделать и для SVG-элемента. Но, так как SVG-изображения и их внутренние механизмы хранятся прямо в DOM, SVG обычно рассматривают как технологию, используемую в тех случаях, когда создают проекты, отличающиеся доступностью для людей с ограниченными возможностями.

Другими словами — можно создать SVG-изображение, с элементами которого смогут работать ассистивные технологии, помогающие своим пользователям ориентироваться на веб-страницах.

Текстовые данные, являющиеся частью изображений, это тоже тот случай, когда предпочтительнее использовать SVG. В SVG даже имеется специальный элемент — <text>. Он позволяет выводить чёткие символы текстов, его воспринимают ассистивные технологии. В случае же использования для визуализации текстов элемента canvas, такие тексты нередко выводятся некачественно, выглядят размытыми.

Canvas лучше подходит для работы с изображениями на уровне отдельных пикселей


Ниже мы приведём несколько таблиц, составленных на основе сравнения SVG и canvas различными экспертами. В одном из таких сравнений, выполненном Сарой Драснер, сказано, что с помощью canvas можно заставить пиксели танцевать. Это, конечно, шутка, но, в сущности, так оно и есть.

Canvas отлично подходит для создания интерактивных изображений, содержащих множество сложных деталей, градиентных переходов цветов и прочего подобного. Именно по этой причине canvas используется при разработке гораздо большего количества браузерных игр, чем SVG. Хотя, конечно, всегда можно найти отклонения от общих тенденций. Вот, например, игра, графика которой создана средствами SVG.


SVG-игра

Обратите внимание на то, что её графическая составляющая очень проста и выглядит достаточно «векторно».

На SVG-изображения можно воздействовать с помощью CSS


Выше мы уже говорили о том, что SVG-элементы хранятся в DOM, и о том, что доступ к этим элементам можно получить из JavaScript-кода. В случае с CSS эта история повторяется:

<svg viewBox="0 0 100 100">
  
  <circle cx="50" cy="50" r="50" />
  
  <style>
    circle { fill: blue; }
  </style>
  
</svg>

Обратите внимание на то, что в примерах блоки <script> и <style> размещаются внутри блока <svg>. Это — совершенно нормально. Но если учесть то, что SVG-элемент находится в обычном HTML-коде, то окажется, что внутренние блоки <script> и <style> вполне можно из него убрать. Кроме того, если нужно, можно воздействовать на SVG-элемент с помощью внешних стилей и скриптов.

Вот большой материал о свойствах SVG-элементов и CSS. Самое важное здесь это то, что всё, что можно делать с элементами страниц средствами CSS, относится и к SVG. Например — это использование псевдокласса :hover и анимирование элементов.

Вот пример анимирования элемента <circle> средствами CSS.

<svg viewBox="0 0 100 100">
  
  <circle cx="50" cy="50" r="50" />
  
  <style>
    circle { fill: blue; animation: pulse 2s alternate infinite; }
    @keyframes pulse {
      100% {
        r: 30;
      }
    }
  </style>
  
  <script>
    document.querySelector('circle').addEventListener('click', e => {
      e.target.style.fill = "red";
    });
  </script>
  
</svg>


Анимирование элемента SVG-изображения средствами CSS

Комбинация SVG и canvas


С технической точки зрения технологии canvas и SVG нельзя назвать взаимоисключающими. Например, SVG-изображения можно выводить в элементы <canvas>. При этом, как можно видеть в данном примере, SVG-изображения, выводимые в элемент <canvas>, вполне могут оставаться весьма чёткими и качественными.


Вывод SVG-изображения в элемент <canvas>

Теперь давайте рассмотрим несколько таблиц, в которых обобщены сравнения SVG и canvas, выполненные различными экспертами.

Сравнение SVG и canvas


?Рут Джон


Вот проект, на основе которого построена следующая таблица.
Возможность
SVG
Canvas
Векторная графика
+
Растровая графика
+
Доступ в DOM
+
Доступность
+
±
Вывод текста
+
+
Вывод градиентов и паттернов
+
+
Поддержка CSS-анимации
+
Поддержка CSS-фильтров
+
+
Поддержка SVG-фильтров
+
+
Поддержка вывода файлов изображений и видеофайлов
+
Экспорт содержимого элемента
+
Управление отдельными пикселями
+
Доступ из JavaScript
+
Производительность анимации
±
+
Поддержка вычислений, выполняемых за пределами главного потока
+

?Сара Драснер


Следующая таблица составлена на основе этого твита.
DOM/Virtual DOM
Canvas
Преимущества Отлично подходит для UI/UX-анимации. Танцуйте, пиксели!
Отлично подходит для вывода SVG-изображений, независимых от разрешения. Отлично подходит для вывода 3D-графики и для других подобных вариантов использования.
Легко отлаживать. Удобно управлять множеством движущихся объектов.
Недостатки Изображения создаются из множества отдельных объектов. Сложнее обеспечить доступность содержимого.
В свете предыдущего минуса оказывается, что при анимации SVG-изображений нужно проявлять осторожность. В стандартном виде canvas-изображения зависимы от разрешения.
Сложно организовать взаимодействие пользователя с отдельными элементами изображения.

?Ширли Ву


В основу следующей таблицы положен этот твит.
SVG
Canvas
Преимущества
Легче изучить.
Очень высокая производительность.
Легче организовать реакцию на воздействия пользователя.
Легче обновлять.
Легче анимировать.
Недостатки
Возможна необходимость в использовании сложных DOM-структур.
Сложнее изучить.
Низкая производительность при работе с большим количеством элементов.
Сложнее обрабатывать воздействия пользователя.
Для анимации объектов нужно писать собственный код.

Многие считают, что для работы с большим количеством объектов (по словам Ширли — это когда их больше 1000) лучше подходит canvas.

SVG — это стандартный выбор. Canvas — это запасной вариант


Вот ответ на мой твит по поводу вариантов использования SVG и canvas. Автор этого ответа говорит, что выбор между SVG и canvas нужно делать так: «Используйте canvas тогда, когда не можете использовать SVG». Среди ситуаций, в которых не получается нормально пользоваться SVG, можно отметить такие, в которых нужно анимировать тысячи объектов, работать с каждым конкретным пикселем изображения, и так далее.

Итоги


В начале этого материала мы привели два типичных варианта использования SVG и canvas. Вернёмся к ним и расширим их описания с учётом того, что мы только что узнали.

  • Нужно нарисовать небольшую иконку? Это, безусловно, территория SVG. Дело в том, что описание SVG-изображения хранится в DOM, в результате SVG отлично подходит для того, чтобы нарисовать что-то вроде значка на кнопке. Не стоит и говорить о том, что на SVG-изображения можно влиять средствами CSS, и, с помощью JavaScript, подключать к их элементам обработчики событий.
  • Нужно создать интерактивную браузерную игру? Тут, определённо, нужна технология canvas. Браузерная игра, наверняка, будет содержать множество движущихся элементов и сложных анимаций. Элементы игрового мира будут взаимодействовать друг с другом, что означает определённые требования к производительности. Для решения таких задач отлично подходит canvas.

Надо отметить, что между этими двумя крайними вариантами есть большая промежуточная зона. Я, например, как веб-разработчик и дизайнер, считаю, что SVG удобнее с практической точки зрения. Я даже не знаю, стал бы я делать некий реальный проект с использованием canvas. Пожалуй, отчасти это так из-за того, что я недостаточно хорошо знаком с canvas. А с SVG я знаком неплохо. Я эту технологию изучал, написал о ней книгу. Как результат — я знаю об SVG достаточно для того, чтобы эта технология помогала бы мне делать то, что мне нужно.

Уважаемые читатели! В каких ситуациях вы используете SVG, а в каких — canvas?


Комментарии (7)


  1. kahi4
    19.11.2019 14:26

    А почему canvas не подходит для векторной графики? Да, придется от чуть меньше до чуть больше написать ручками, фактически придется найти движок, но на канвасе можно рисовать как угодно, в том числе и векторной графикой. http://processingjs.org/ или http://paperjs.org/ например. Как преимущество — можно смешивать векторную и растровую графику одновременно.


    Доступ из JavaScript

    Это почему вдруг к svg нет доступа из JS?


    1. SerafimArts
      20.11.2019 04:15

      Скорее всего имелся ввиду результат. У канваса он всегда растрируется при рендере, что можно запросто увидеть включив зум/масштабирование.


      1. kahi4
        20.11.2019 13:36

        SVG тоже всегда растрируется (растеризуется?) при рендере. Просто браузер берет на себя обработку зума.


        Канвас гораздо более низкоуровневый. Собственно, от сюда и все различия. Нужно сделать что-то быстро и на коленках — svg хорош (но не идеален), но если хочется гибкости и возможности рисовать что вздумается либо быть хоть немного уверенным, что это будет работать быстро (svg с css анимациями может быть очень тормозным, если рисовать чуть больше, чем 5 линий) — брать канвас. Но да, придется ручками делать то, что с свг уже дано.


  1. DmitryOlkhovoi
    19.11.2019 18:56
    +1

    Для себя смотрю по таким критериям
    — Если элементов очень много, то лучше canvas. Тысячи HTML SVG элементов в DOM это жуткие лаги.
    — Если слишком богатая анимация, то canvas
    — Если элементов не много, то лучше svg. Так как это html элементы, можно накладывать стили, обрабатывать клики и так далее. С canvas же надо повозиться


  1. kovserg
    19.11.2019 23:22

    А почему ни слова про «canvas+hdpi=секас»?


  1. mSnus
    20.11.2019 05:09

    Делал как раз только что карту метро, чтобы можно было на ней в бэкэнде расставить точки ("на каких станциях магазины"), а во фронтэнде на них по клику и подгружать окно со схемой проезда и прочие подробности. Карта должна масштабироваться под размер окна и зумиться по клику.


    Сделал всё в Adobe Animate на canvas, промучился там, но сделал.


    Получил на выходе 190К библиотек CreateJS + 18К сами файлы + 214К графика, итого 422К! И всё это дико тормозит на загрузке. И CreateJS выдаёт всякие дебильные ошибки вроде "Uncaught An error has occurred. This is most likely due to security restrictions on reading canvas pixel data with local or cross-domain images." Отдельные точки в DOM не видно.


    Плюнул на всё потраченное время, переделал на чистом JS в GWD. 158К графика + 13К все файлы = 171К, втрое меньше. Работает мгновенно, отлаживать удобно. Каждая точка — нормальный HTML-объект и так далее.


    В общем, чтоб я ещё раз полез в этот глючный Animate и работу с canvas… только если работа с тяжелой графикой типа игры, где время загрузки неважно и где это не компонент сайта, которому нужно взаимодействовать с другими. А жаль, лет 10 назад я бы с удовольствием писал всё это на Flash и об альтернативах и не думал!


  1. domix32
    20.11.2019 12:45

    Интересно какая у них разница в потреблении памяти