From Bitmap Images to Inline SVGs

 7 min. to read
 No comment yet
  (last mod.: 2021-10-23)

When I started this website, I wanted my personal illustrations to feel handdrawn. After two years, those illustrations were a collection of charts and graphs. There are more precise ways to convey that type of information. SVG is one of them, with a generally lighter footprint and better accessibility, so I went for it.

An Assessment of the Images Concerned #

What Images #

The images I had drawn were as follows:

  • a bar for representing proportions;
  • a donut chart;
  • two bar charts (one horizontal and one vertical);
  • a Venn diagram;
  • a graphical resolution of an inequation.

When I decided to go for SVG, I also included a treemap I had made in PowerPoint and four Gantt diagrams generated by mermaid.

That’s a total of 10 bitmap1 pictures that could be replaced with SVGs. The Gantt diagrams would remain external images (SVG in an <img> tag) while all others would become inline SVGs (SVG included inside the page’s DOM).

Those images were split across 4 pages.

What Impacts for Each Image #

Including an image in a webpage has some immediate impacts. The first one is that it is one external static resource to load — one additional HTTP query.

It’s even a bit worse in my case: I use lazy loading, but I put a placeholder for each image that is not yet loaded, so that the layout won’t change when it is. This means that, for each picture, the placeholder and the final image are loaded (if the user scrolls the whole page), making each image two additional HTTP requests.

What’s more, each image is resized to up to six dimensions to fit most devices (so that smaller screens won’t load a high resolution picture, for instance). This means the space occupied by each image on my hosting machine is multiplied by the number of resizes I make: to avoid impact on browsing, I add impact on building (CPU, time) and storage.

What Gains for SVG #

For the reader, vector images would render better at any scale than my resized image set, and should be more accessible for people with handicaps.

For me, there also is a gain in maintenance. I’ve been considering adding a language to this website. Translating vector images, which embed actual text, would be easier than remaking images and changing the labels.

I’ve also begun looking in img-optimize for serving smaller images, but PNGs are slow to process. Unfortunately, PNG is the format my “handdrawn charts” are saved in. Replacing those with SVG also allow me for a not-insignificant gain in time while optimizing images and generating WebP equivalent.

The Process #

What I Did #

First, I searched a lot. There are actually very few solutions to generate charts in SVG without having to include JavaScript in your page. My goal was to represent static data, I didn’t want to rely on external dependencies or libraries for that.

I found one or two free SVG charts generators, but they were globally limited and unsatisfactory. So I read, and I read, and I read a bit more. CSS-Tricks featured a nice post about this topic (graphs, pie charts, animations, with or without JavaScript), and redirected to a tutorial for donut charts in SVG which helped me a lot. Sitepoint also had great tips for making accessible SVGs

Then I experimented, making each chart one by one, in my text editor. This was slow and I had to tune things a lot, but I actually learned a lot I didn’t know yet about how SVG works. I also used some examples generated by D3.js to understand how they agenced things and build on that. The treemap still features sizing computed by this library, but I had to change many things for readability.

Many of the styling has been included inside the site’s CSS, making it a bit heavier, but for the general benefit.

What I Discovered #

I never really studied SVG until now. Of course, I knew the basic principles, but I never wrote one on a text editor.

What’s interesting is looking at what JavaScript libraries generate. Some of them create groups that they translate. In the case of the bar chart, D3.js created a group for the X axis, that it would transform that way, and an inner group for each graduation that undergoes the same treatment (translations in translations).

It’s a bit complicated so, once I discovered the viewbox can start at negative coordinates, I chose to update this so that (0, 0) would be the origin of my chart, making it easier to place my data and axis, changing when requried.

The scale is also a topic here: JavaScript libraries seem to compute how large the image should be and then make all the necessary calculations. That’s a hell for update and maintenance, and I’ve used my good ol’ calculator more than once. On most of my charts, I chose a simpler scale (e.g. 1/10 or 1/1000), which allowed me to easily get precise positions by calculating all in my head.

For accessibility, I discovered through the donut chart tutorial that <title> and <desc> tags can be added to almost any element in the SVG, allowing for a more precise documentation than a single alternative text.

Quantifying the Results #

Global Site Size #

At the time I am writing these lines, the English version of Keyboard Playing consists in 146 pages.

Size with imagesSize with SVGsDifference
19.84 MiB17.49 MiB-2.35 MiB

That may not look like much but replacing 10 bitmap pictures with SVGs carrying the same information saved 12% of disk storage on the hosting machine.

That’s not the most interesting, though.

Measuring the Impact on a Page #

I wanted to see what it meant for one page, so I chose to analyze a bit more one that I thought would be a perfect example: my post about the footprint of digital technology.

It’s one of the heaviest page of the site. It includes three charts, five other bitmap pictures and one (external) SVG image. Basically: long page, long text, long DOM, several external resources, three of which were replaced with inline SVGs.

How did it translate?

MeasureWith imagesWith SVGsDifferenceRel. diff.
Weight of the minified HTML45.69 KiB49.79 KiB+4.10 KiB+9,0%
Weight of the minified CSS12.55 KiB14.29 KiB+1.74 KiB+13.9%
Elements in DOM514650+136+20.9%
External resources2317-6-26.1%
Total transferred weight736.95 KiB486.53 KiB-250.42 KiB-34.0%

So, what do we see here?

  • The size of the page and its complexity increased, which is to be expected since we replace simple <img> tags with textual, meaningful code.

  • The size of the CSS increased too, but that’s normal since we added new rules for SVGs and charts.

  • The total transferred weight has gone down by a third, which was one of the main objectives.

I ran an analysis with the GreenIT-Analysis plugin and my Ecoindex score for this particular page is still down to C.

About Accessibility #

I audited the same page through Wave, before and after the modification. I saw no substantial change. Some warnings related to the pictures have disappeared (long alternative texts, noscripts related to the lazy loading), some ARIA has been picked up, but nothing to congratulate me on making the information more available.

One thing I’d love to do some time in the future would be to test my own site with a screen reader, but I’m not this far yet.

Keeping My Feet on the Ground #

This is not an absolute success. The page I took to measure the enhancement is the one with the heaviest footprint on the whole website (which is kind of ironic given its topic).

Ten pictures were replaced across four pages. The 160 others are just subjected to the heavier CSS with no other change to show for it. Do you have ideas to make things a bit better yet?

  1. As opposed to a vector image. JPG and PNG are bitmap formats. ↩︎