Exploring Using SVG Over HTML/DOM for Performance

Greg Bate
4 min readOct 19, 2019

While plotting elements in HTML/DOM tends to be the traditional way of laying out content, I want to see if I can do the same thing in SVG and get more performance.

The Plan

  1. Learn how to draw a component in both HTML and SVG
  2. Build an interface that tests both methods and can benchmark multiple levels of complexity.
  3. Hopefully, arrive at a result.

The Example Interface

I will make an example that pushes HTML and SVG to its limits as well as show how SVG can be rendered just like HTML.

The interface will consist of multiple lanes holding projects that occupy days. The projects need to be clickable, and the labels need to be fixed-width, sometimes overflowing smaller projects:

I will also place the interface in a container that is constantly resizing to minim zooming. I want to see how both situations handle constantly resizing.

The Project Structure

A project needs to have some information so we can plot it on a timeline. Assuming the timeframe is 1 year, here is a good structure:

SVG Layout (bear with me)

Layers

Drawing multiple child SVG layers inside a root SVG will enable some great functionality. You can stack elements in a way that makes sense and take advantage of multiple ways to place elements.

Capture user events on any layer if they are inside a root image.

ViewBox Placement

ViewBox is great since it allows for easy or no calculations. For instance on a timeframe of 365 days, and a project always taking up 1 day, I can establish 365 units on the x-axis. preserverAspectRatio="none" is also required since the width is dynamic and the height is fixed. Now we get simple syntax with no calculations ie:

Vue Syntax

Rect Percentage Placement

Once we break out of ViewBox that places everything solely on the established units, we can position elements with percentage and keep them a static size. A rect can be placed from the center of the project and transformed outward:

Vue Syntax

Text Percentage Placement

The text element is placed in the same way as the rect but the transform/translate isn’t required since we can use alignment-baseline and text-anchor to expand outward:

Vue Syntax

Note: Some browsers don’t support alignment-baseline so I had to add transform="translate(0 4)" to bump the text down a bit based on the text size

Working SVG Example

HTML Layout

Luckily HTML will have a lot easier syntax than SVG. We can place the project box with percentage and rely on CSS & flexbox to place label centered outward:

Working HTML Example

Now that we know how to draw the interface in both HTML and SVG time to move forward with benchmarking.

Data Generation & Testing

To be able to test HTML and SVG it would be nice to be able to adjust multiple variables on the fly:

  1. Number of lanes
  2. Number of days (ie more than 1 year)
  3. Project length (random between min & max)
  4. The gap between projects (random between min & max)
  5. Lane height and margin between lanes
  6. Amount of time between resizing
  7. Rendering method (HTML or SVG)

Here We Go:

I created a quick UI to test both HTML and SVG. Check out the UI here and play with the settings.

Results Time!

Visually the performance seems to be near identical with HTML and SVG. Monitoring CPU and memory usage they are about the same as well. SVG seems to act a little smoother inside a CSS transition.

meh

I was hoping for something more impactful.. if you get different results let me know!

More SVG Tips!

  1. You place multiple elements at once by putting them inside a <g> (group) and translate/transform by pixels or units.
  2. If you want to do the same thing (place multiple elements at once) by percentage (translate/transform doesn’t support percentage) use an <svg x="25%" y="20px">. All inside elements will be positioned relative to the SVG position.
  3. If you want to position a group of elements inside an <svg> and have them expand outward, make sure to add a style="overflow: visible;” to the <svg>.
  4. The browser tries to not draw elements if it thinks it’s not in view. If you ever encounter elements not drawing apply a transform: scale(1, 1) style to the root<svg>, this will force the entire <svg> to draw.

That’s it, thanks for reading!

--

--