The HTML5 canvas has the potential to become a staple of the web, enjoying ubiquitous browser and platform support in addition to widespread webpage support, as nearly 90% of websites have ported to HTML5. So, why hasn’t the canvas become a staple of the web?
The canvas tag on StackOverflow accounts for fewer than two percent of all questions, and Google Trends shows searches for “canvas” have no more than quadrupled over the past five years. There are a number of possible explanations, but instead of debating its past, we’ll address advantages and seeming disadvantages of the HTML5 canvas — including time-tested solutions for those drawbacks. Below are brief summaries of the various drawing techniques and the main advantages and disadvantages of each:
- Document Object Model (DOM): The most familiar of the three techniques we will discuss. Albeit flexible and easy to work with, offering amenities like click event handlers, your typical div comes with overhead. Its main selling point is ease-of-use and its Achille’s heel is efficiency in terms of memory and rendering speed.
- Scalable Vector Graphics (SVG): The halfway mark between ease-of-use and fine-grained control. SVGs are likewise a part of the DOM but are designed for high-fidelity, large graphics as the name suggests. Unlike the DOM, SVG supports a wide range of pre-built shapes such as a circle or polygon. Its biggest pro is large graphics and its downfall is many graphics.
- HTML5 canvas : The canvas gives you, the developer, finer grained control over rendering but comes at the cost of having to manage every detail manually, such as a hover state. The canvas’s biggest advantage is precisely the opposite of SVG’s: it’s great at managing many objects.
- WebGL : The newest of these technologies and fully-fledged 3D-capable engine. This is accessible via Canvas’s 3D context but also supports 2D; furthermore, being extremely low-level, it is extremely efficient: WebGL can handle both many objects and large objects.
In sum, the list above offers a spectrum of abstraction layers, where the least abstraction is the most efficient (canvas and WebGL) and the most abstraction is the least efficient (SVG and DOM). However, both the canvas and WebGL options have a few additional advantages, both old and new, that make it more enticing as a middle ground: third-party libraries that increase ease-of-use and support for asynchronous rendering, making it even more efficient:
Third-party libraries : A number of third-party libraries offer abstractions on top of WebGL and canvas, providing a middle ground between the abstractions provided by the DOM and the lack of abstractions provided by the canvas. As our cheat sheet below will discuss, some third-party libraries additionally switch between rendering techniques to maximize efficiency, removing the need for you to pick. Here are a few of the most popular canvas and webGL rendering libraries:
- pixi.js (22.4k stars, created 2013): 2D WebGL renderer with a canvas fallback and an emphasis on speed, with support for plugins of its own
- EaselJS (7.2k stars, created 2011): interactive object models on canvas, with support for mouse interactions and nested objects
- fabric.js (12.3k stars, created 2008): interactive object models on canvas, with support for SVG via SVG-to-canvas and canvas-to-SVG conversions
Offscreen canvas: To further enhance canvas performance, utilize the Offscreen Canvas. Granted, it’s only supported by Google Chrome, with experimental support from Opera and Firefox. However, the offscreen canvas can boost performance significantly: the offscreen canvas can be leveraged to pre-render expensive visuals, such as text, more efficiently (jsperf), and using web workers, canvas rendering can be offloaded to an asynchronous thread (discussion, demos).
In short, the canvas and WebGL are more performant than the DOM, and with third-party libraries, its ease-of-use is comparable; furthermore, growing browser support for additional web standards have the potential to further boost canvas performance. Both benefits combined have the potential to further canvas adoption across websites, lowering the barrier to entry and bolstering the benefits of using the canvas. To understand why the canvas is much faster than the DOM, we’ll need to understand rendering styles.
To explain the efficacy of the canvas, we have to distinguish between two rendering styles in computer graphics: immediate mode and retained mode , represented by the Canvas and DOM, respectively.
In immediate mode , the client issues calls that results in the immediate display of graphic objects. In our case, every canvas function call results in a graphic object drawn immediately. Regardless of which parts of the canvas are updated, the entire canvas must be redrawn each time, barring optimizations the client may have already made. This means that the client must maintain a model of objects in the canvas. Below, blue represents the pixels and API calls you as the developer directly control.
By contrast, in retained mode , client calls do not result in immediate display of graphic objects. Instead, the client calls update an internal model. In our case, developers specify HTML and associated CSS, and the browser handles when and how to display these graphics. This allows the browser to further optimize when and which objects are rendered. For example, calls to requestAnimationFrame benefit from this built-in optimization. Below, blue (again) represents the API calls you as a developer directly control. However, the red represents the abstractions that the browser handles for you, including maintaining an internal model and updating the graphic objects.
The former, immediate mode, offers flexibility but requires meddling in details. And the latter, retained mode, limits flexibility but abstracts away details. These paradigms explain the philosophies behind the canvas and DOM respectively. Below, we outline the implications of these two operating modes in more detail.
Here is a brief cheat sheet outlining the pros and cons of each method listed above. These pros and cons are largely rooted in the aforementioned rendering styles; we’ve only outlined a few of the most pressing implications. For our comparison below, it is worthwhile to combine both the SVG and DOM as contenders, as they share the same benefits and downfalls as well as similar interfaces.
Document Object Model (DOM) and Support Vector Graphics (SVG):
Pros : ease-of-use
- Responsiveness is built-in and easily supported with the proper CSS
- Redrawing frames is handled automatically via browser rendering
- Animations are pre-designed, configurable, and extensible via CSS
- (Per its name) Supports object-level interactions, such as clicking a div
- Hardware acceleration for transforms
Cons : inefficiency
- Not suited for complex graphics: memory-intensive and will result in slow rendering
- Coarse control over rendering, animation, etc. Abstraction restricts customizability
- Fast and flexible: fine-grained control over when, how pixels are rendered
- Hardware acceleration for all rendering, animation etc.
- Better than SVG for complex graphics and when there are many objects to manipulate
Cons: less abstraction (but this can be overcome with third-party libraries)
- No object-level interactions built-in, as the canvas works on a pixel-level basis
- Slow when drawing large objects or when managing a large canvas
- Does not automatically adjust to display pixel ratio, resulting in blurry text
- Increased code complexity for animations, basic configurations etc.
- The fastest and most flexible: low-level interactions with pixels on the screen
- Only technology, of the three options here, optimized for 3D rendering
- Hardware acceleration for all rendering, transformations, animations etc.
Cons: even less abstraction (but this can, again, be overcome with third-party libraries)
- Requires an understanding of 3D rendering and mathematics
- Even further increased code complexity for animations, basic configurations etc.
Note that in each of the options above, and as we mentioned in the introduction to canvas, code complexity can be easily ameliorated with a proper library; for example, a popular tool of choice for 3D webGL is three.js and a popular choice for 2D webGL is pixi.js. Each of these libraries abstracts away details and removes the need for prerequisite knowledge. With the right library, you as the developer can interpolate between the three methods above, switching backends where necessary. In fact, a few libraries already switch backends for you automatically. For example, the data visualization library d3.js switches from SVG to webGL when switching from 2D to 3D, and pixi.js uses webGL with a canvas fallback where needed.
Armed with the pros and cons above, you now have guiding principles for when to use which technology, at a coarse level. Here are several scenarios to further illustrate the above list, enumerating a few common scenarios and which technology to use for each.
A game with a static UI, such as a score display and a fixed option menu
- SVG , since large parts of your interface are fixed and can benefit from not redrawing
A game’s core display, with hundreds or even thousands of animated, moving characters
- Canvas for the complexity of graphics, in addition to the large number of entities
- WebGL for three-dimensional games
A website logo with basic animation
- SVG , since this logo should be crisp at all resolutions, which SVG supports without external libraries. CSS can provide basic animations. It is worth mentioning that canvas is overkill.
Given the above high-level overview, we will now dive into more concrete numbers: the benchmarks below will quantify tradeoffs more precisely and give you numbers to base more fine-grained decisions off of.
In this experimental section, we will answer two questions regarding the tradeoffs between SVG and canvas.
- How many objects is each technology best for?
- What size objects is each technology best for?
It’s worth mentioning the experimental setup, for those who wish to reproduce these results: The following experiments are run on Google Chrome v73 on a 2018 Macbook Pro with an Intel Iris Plus graphics card. Below each experiment will be the source code.
How many objects is each technology best for?
Below, we benchmark speed per number of objects, in the thousands. Note that SVG is no match for canvas at any point. However, note this scale is fairly large, graphing render time for up to 1 million objects. For fewer objects, the differences are minimal but differ by an order of magnitude: to draw 1000 objects, SVG requires ~10 ms whereas canvas requires 1 ms. This difference only magnifies with more and more objects, but even for sizable numbers of objects, it appears the difference is minuscule.
What size objects is each technology best for?
- Changing the size of the object alone did not appreciably change the render time, as this JSFiddle demonstrates: https://jsfiddle.net/alvinwan/0mbnLfod/ We range the object size from 10,000 x 10,000 to 1 million x 1 million, all of which take ~1ms. A similar experiment with SVG likewise did not exhibit appreciable differences in render time
- Changing the canvas size likewise does not affect the render time. Drawing 10,000 objects takes ~8ms whether on a canvas 10,000 x 10,000 or on one 100 x 100, https://jsfiddle.net/alvinwan/08m42e56/8/
Given the current experimental setup, it appears as though size of the object and size of the canvas do not affect either the canvas or SVG techniques.
In sum, the overhead of DOM rendering is more poignant when juggling hundreds if not thousands of objects; in this scenario, canvas is the clear winner. However, both the canvas and SVG are invariant to object sizes. Given the final tally, the canvas offers a clear win in performance.
This is only the start of a performance discussion surrounding canvas and other graphics techniques for the browser. Even after having decided on SVG, canvas, webGL, or some mixture thereof, there are then efficiency concerns for commonly used operations, such as canvas drawing and polygon fills, how to efficiently redraw, whether multiple canvases is worth the overhead etc. The performance optimizations are endless, and the combinatorial numbers of ways to combine all three techniques only further complicate the issue. However, at the end of the day, simplicity is just as important a factor, and the cheat sheet above should suffice for you to determine whether a further performance investigation is warranted or not; for an animated figure in a blog post, it may not be worth it. For a full-page interactive featuring real-time multiplayer, every ounce may count.
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.