SVG, Canvas, WebGL, WebGPU — кто здесь вообще главный? Большой тест 2D-графики в браузере
- четверг, 27 ноября 2025 г. в 00:00:09
В последние годы спрос на 2D/3D-инструменты в веб-сервисах растет довольно стремительно, технологии развиваются, появляются новые подходы и библиотеки — а вместе с ними растёт и путаница: что где использовать, где грань между похожими решениями и почему у разработчиков часто возникают противоположные мнения?
Так что я решила устроить небольшой тест 2D-решений: посмотреть, на что они реально способны, понять, почему результаты местами вызывают большое удивление, и ответить себе (и вам) на вопрос: а WebGPU вообще зачем?
Спойлер: всё далеко не так очевидно, как кажется.

Привет, меня зовут Даша. Я занимаюсь веб-разработкой уже больше 5 лет, и последние 2–3 года мои проекты всё чаще касаются веб-сервисов, активно использующих 2D-графику. А чем сложнее становятся сервисы, тем глубже приходится нырять в специфику инструментов и технологий. И когда только приходилось углубляться в это - возникало много вопросов по типу “почему бы не использовать WebGL сразу?”, “почему некоторые сервисы используют svg в редакторе вместо canvas”, “зачем вообще этот ваш WebGPU нужен” и прочее.
Теперь, когда WebGPU активно расширяет поддержку, мне захотелось проверить: а насколько оно вообще разумно для 2D-графики? Поэтому я решила провести полноценный тест, расставить все точки над i и заодно посмотреть на уже устоявшиеся подходы. И вот я тут — делюсь результатами.
Думаю, стоит начать с наших сегодняшних героев. Вот они слева направо:
Canvas — де-факто стандарт 2D графики. Прост в изучении, библиотек — вагон, поддерживается даже на тапочке.
SVG — особых представлений не требует, но когда-то меня сильно удивило, что его используют не только в анимациях.
WebGL — технология, позволяющая запускать графические шейдеры прямо в браузере. Отлично масштабируется и снимает нагрузку с CPU.
WebGPU — новый стандарт, пришедший на смену WebGL. Быстрее, мощнее, перспективнее, но пока ещё не везде поддерживается.
Мы будем сравнивать простую анимацию с шариками, отбивающимися от стен. Код писался при участии Claude и ChatGPT; исходники лежат тут: https://github.com/daashuun/bouncing-balls-test.
Моё окружение:
ОС: Windows 10
Браузер: Chrome 140.0.7339.127 (vsync отключён — не пугайтесь 8k+ fps, всё так и задумано)
CPU: Intel Core i7-13620H
GPU встроенная: Intel UHD Graphics
GPU дискретная: NVIDIA GeForce RTX 4070
Что измеряем:
FPS
CPU usage (старт, среднее, пик)
GPU usage (старт, среднее, пик)
Количество объектов:
1, 100, 1000, 10000, 20000, 30000, 50000, и для WebGL/WebGPU — 100000.
Почему тесты проводятся на двух видеокартах? Потому что Chrome на устройствах с двумя GPU (обычно ноутбуки) по умолчанию использует встроенную графику, а обычный пользователь редко лезет менять настройки под какой-то ваш сервис. Но для чистоты эксперимента хотелось посмотреть и максимальную мощность которая мне была доступна.
Canvas:
кол-во шаров | 1 | 100 | 1000 | 10000 | 20000 | 30000 | 50000 |
fps | 6700 | 4900 | 650 | 67 | 34 | 23 | 13 |
cpu | 55 | 42 | 33 | 29 | 28 | 28 | 26 |
gpu | 100 | 100 | 100 | 100 | 100 | 100 | 100 |
пик cpu | 60 | 47 | 36 | 32 | 32 | 31 | 31 |
пик gpu | 100 | 100 | 100 | 100 | 100 | 100 | 100 |
при открытии cpu | 87 | 64 | 61 | 63 | 54 | 47 | 52 |
при открытии gpu | 100 | 100 | 100 | 100 | 100 | 100 | 100 |
Svg:
кол-во шаров | 1 | 100 | 1000 | 10000 | 20000 | 30000 | 50000 |
fps | 8200 | 1020 | 293 | 29 | 14 | 10 | 6 |
cpu | 52 | 35 | 28 | 24 | 24 | 23 | 24 |
gpu | 90 | 92 | 97 | 71 | 80 | 78 | 72 |
пик cpu | 62 | 42 | 37 | 32 | 29 | 26 | 27 |
пик gpu | 100 | 100 | 100 | 86 | 90 | 91 | 78 |
при открытии cpu | 72 | 63 | 47 | 47 | 38 | 50 | 43 |
при открытии gpu | 100 | 97 | 90 | 65 | 70 | 66 | 52 |
WebGL:
кол-во шаров | 1 | 100 | 1000 | 10000 | 20000 | 30000 | 50000 | 100000 |
fps | 3300 | 1350 | 775 | 94 | 57 | 39 | 24 | 12 |
cpu | 33 | 26 | 35 | 17 | 18 | 18 | 20 | 20 |
gpu | 70 | 51 | 82 | 86 | 76 | 45 | 34 | 47 |
пик cpu | 52 | 34 | 39 | 24 | 23 | 21 | 26 | 21 |
пик gpu | 92 | 70 | 100 | 100 | 83 | 67 | 70 | 68 |
при открытии cpu | 71 | 73 | 68 | 62 | 45 | 38 | 48 | 53 |
при открытии gpu | 76 | 49 | 82 | 82 | 77 | 48 | 34 | 32 |
WebGPU:
кол-во шаров | 1 | 100 | 1000 | 10000 | 20000 | 30000 | 50000 | 100000 |
fps | 4350 | 4100 | 1805 | 250 | 130 | 87 | 55 | 27 |
cpu | 53 | 62 | 36 | 26 | 27 | 27 | 27 | 28 |
gpu | 93 | 95 | 100 | 100 | 100 | 100 | 99 | 100 |
пик cpu | 58 | 70 | 38 | 30 | 31 | 43 | 29 | 30 |
пик gpu | 96 | 98 | 100 | 100 | 100 | 100 | 100 | 100 |
при открытии cpu | 75 | 87 | 63 | 50 | 55 | 52 | 56 | 55 |
при открытии gpu | 98 | 98 | 100 | 100 | 100 | 100 | 100 | 100 |
Для удобства разделила на два графика:


Основные наблюдения
Во-первых — банальности, которые всё же приятно подтвердить:
Canvas после ~10k объектов перестаёт быть эффективным.
WebGPU заметно лучше использует видеокарту по сравнению с WebGL.
Во-вторых — немного неожиданный факт:
SVG при небольшом количестве объектов (<100) оказался существенно эффективнее Canvas, причём нагружает CPU и GPU значительно меньше. Ожидалось, что они будут приблизительно одинаковы.
Зная реальные запросы, могу уверенно сказать: у большинства use-cases количество объектов редко превышает сотню. Так что SVG — весьма хороший выбор. Но если вы строите полноценный редактор или рассчитываете на динамическое количество элементов, будьте осторожны: тест был упрощен, без взаимодействия с пользователем, и в реальности будут проседания.
Переходим к RTX 4070.
Сразу заметила, что для Canvas и SVG разница с встроенной GPU была менее 1%, поэтому для них отдельные замеры не проводились.
WebGL:
кол-во шаров | 1 | 100 | 1000 | 10000 | 20000 | 30000 | 50000 | 100000 |
|---|---|---|---|---|---|---|---|---|
fps | 8750 | 8450 | 2870 | 324 | 169 | 112 | 69 | 34 |
cpu | 62 | 65 | 52 | 33 | 32 | 31 | 30 | 30 |
gpu | 50 | 72 | 49 | 29 | 26 | 28 | 31 | 32 |
пик cpu | 65 | 67 | 54 | 35 | 35 | 36 | 37 | 34 |
пик gpu | 57 | 74 | 58 | 30 | 33 | 29 | 31 | 33 |
при открытии cpu | 90 | 80 | 84 | 59 | 64 | 78 | 65 | 55 |
при открытии gpu | 52 | 73 | 54 | 27 | 24 | 24 | 24 | 25 |
WebGPU:
кол-во шаров | 1 | 100 | 1000 | 10000 | 20000 | 30000 | 50000 | 100000 |
fps | 4900 | 4500 | 2150 | 316 | 152 | 99 | 62 | 30 |
cpu | 69 | 54 | 40 | 21 | 19 | 19 | 19 | 18 |
gpu | 68 | 73 | 74 | 28 | 17 | 18 | 20 | 23 |
пик cpu | 72 | 57 | 44 | 25 | 26 | 23 | 72 | 24 |
пик gpu | 71 | 74 | 74 | 28 | 19 | 21 | 22 | 25 |
при открытии cpu | 62 | 63 | 70 | 42 | 53 | 46 | 59 | 37 |
при открытии gpu | 65 | 70 | 74 | 27 | 13 | 11 | 17 | 11 |


И… что это вообще было?
Этот тест, честно говоря, дал больше вопросов, чем ответов. Разберём ключевые:
Почему WebGL оказался быстрее WebGPU?
Почему увеличение FPS при переходе на дискретную GPU у WebGPU едва достигает 10–15%, тогда как WebGL вырастает в разы?
Понаблюдав за нагрузкой, нашлась причина: в WebGPU при смене видеокарты снизилась нагрузка и на CPU, и на GPU, а это плохо — оба простаивают, значит есть “бутылочное горлышко”. В WebGL же CPU стал загружен сильнее, а GPU — меньше, что логично: видеокарта утыкается в CPU.
Разобравшись, выяснилось: самая большая проблема — запись данных в буфер каждый кадр.
Решение: переписать вычисления на compute-shader, чтобы не перезаписывать буфер.
Получаем:
кол-во шаров | 1 | 100 | 1000 | 10000 | 20000 | 30000 | 50000 | 100000 | 500000 |
fps | 5550 | 5600 | 5650 | 3166 | 1736 | 1196 | 736 | 375 | 76 |
cpu | 67 | 58 | 55 | 42 | 31 | 24 | 22 | 18 | 17 |
gpu | 45 | 30 | 25 | 100 | 100 | 100 | 100 | 100 | 100 |
пик cpu | 71 | 62 | 59 | 57 | 35 | 28 | 25 | 22 | 23 |
пик gpu | 48 | 40 | 43 | 100 | 100 | 100 | 100 | 100 | 100 |
при открытии cpu | 78 | 81 | 68 | 62 | 43 | 50 | 47 | 48 | 42 |
при открытии gpu | 189 | 29 | 27 | 100 | 100 | 100 | 100 | 100 | 100 |


Отлично! Это то, что нужно - теперь WebGPU действительно дал понять на что он способен. После оптимизации даже пришлось поднять максимальное число шаров до 500 тысяч, чтобы FPS опустился к разумным 76.
Важное наблюдение
При малом числе объектов WebGPU с compute-шейдерами работает медленнее — потому что моя видеокарта имеет 5888 вычислительных блоков. Пока количество задач меньше этого числа, GPU фактически простаивает. Но когда объекты наконец «заполняют» все блоки — начинается магия (теоретически можно добиться ещё лучших результатов, подбирая количество объектов, кратное числу блоков, но в рамках эксперимента это не требовалось.)
Мы тестировали максимально простую логику без пользовательского взаимодействия и без логики реального приложения. Фреймворки тоже не использовались — поэтому в реальности показатели будут хуже, в рекомендациях учтен этот момент.
Если объектов до 50
→ SVG
Лучший вариант для большинства анимаций, интерфейсов и редакторов, ограничивающих количество элементов.
Но если количество объектов задаёт пользователь — это риск.
Если объектов до 5000
→ Canvas
Покрывает 80–90% бизнес-кейсов.
Широчайшая поддержка, куча библиотек, готовых решений и документации. Если кейс не специфический — берите Canvas, не прогадаете.
Если объектов больше
→ WebGL
Сложнее Canvas, но проще и стабильнее WebGPU.
Приложения уровня Figma и Miro чаще всего используют WebGL, и, думаю, мне не нужно рассказывать, насколько хорошо они работают при большом количестве объектов.
Если кейс специфический (симуляции, сложная математика, ML, 3D…)
→ WebGPU
Это ваш выбор.
Такие пользователи обычно технически подкованы и в случае необходимости смогут разобраться и переключить видеокарту.
Также выбирайте WebGPU, если:
вам подходит WebGL,
проект разрабатывается год+,
старые браузеры поддерживать не нужно.
К моменту релиза вашего приложения WebGPU вполне вероятно будет поддерживаться повсеместно (сейчас ещё есть проблемы на некоторых мобильных устройствах и в Linux).
В итоге можно сказать, что выбор технологии для 2D-графики — это не вопрос «что лучше», а вопрос «что подходит вашему сценарию». Все решения закрывают свои ниши, и каждый инструмент отлично справляется с задачами, для которых он был создан. Но если понимать ограничения и особенности каждого подхода, можно избежать множества проблем и сделать продукт не просто рабочим, а действительно оптимальным.