When CSS wasn’t enough: Why you shouldn't be scared of writing your own SVG
Ehud Winograd, Wed Jan 27 2021, 7 min
CSS Blinds Meme
I like CSS. I'm sometimes ashamed to admit it, given how some people seem to passionately hate it, and I’ll admit CSS can seem pretty crazy at times. I still occasionally stumble into an MS-Word cliché style scenario where I have no idea why adding a button suddenly made my sidebar go AWOL, but I don’t usually feel very surprised or limited by the technology, and I know how to get to the results I want.
Once you work with CSS for a while, you learn that you can usually break any shape or design down to somewhat easily-styled square elements and borders, and that there's usually a MacGyver-like solution for the non-obvious shapes like triangles, arrows, or stars in CSS.
This post, however, is about a task for which CSS just wasn't enough. That day I was first confronted with my hubris, I dipped my toe into the world of writing custom SVG, and I gained a powerful tool in my arsenal.

The Premise

Some background: at Oribi, we provide analytics services for our customers' websites. We collect all the clicks, visits, and interactions (collectively called "events") on the website and provide insights about changes or correlations in the data.
Recently, we added a feature that lets our customers export their events from Oribi to other platforms like Facebook Analytics and Google Ads so they can adjust their ad campaigns automatically. Our designer tried to make it clear which event is exported to which platform, and eventually sent me the new page's ambitious design:
A mockup of the page: two columns of boxes (events on the left and platforms like FB on the right) and curved connecting lines between them

My first thought was: this might be slightly challenging to recreate, but there’s probably a CSS feature I can use to take care of it. Little did I know…

Taking My Usual Approach With CSS

I discussed this design with one of my colleagues. It went a little bit like this:
Colleague: So, this new page - looks like it'll be so fun to make!
Me: Definitely! I can't wait to start :)
Colleague: I tried looking for a JS library for the connecting lines. I didn't find anything that fits perfectly, but I found several that I think we can tweak a bit until they look kinda like the design.
Me: I'm not sure we'll need a library for this—it looks pretty simple. I think we can probably use a couple of divs to make each line, no problem.
Colleague: Please do me a favor: don't try that in CSS. It'll just take longer, the code will be more complicated, and it'll probably not look as nice as using a dedicated library that's using HTML canvas.
Me: Nah, I'm pretty sure we can make it with some border-radius in CSS. I'm going to give it a try, but I'll check out those libraries if I see it's taking too long.

So I got to work. Pretty quickly I got something that looked like it might have some potential: a single div element that uses two CSS-rounded corners to achieve a smooth curved connector.
Not as stylish as the original design, but not bad at all. Another notch in the pure-CSS solutions belt!

A Crisis of Faith

At least that's what I thought until I checked what it would look like for a shorter connector (connecting boxes with small vertical distance), or what it would look like to layer multiple connectors, like the design requires:
That looked nothing like the original elegant design! The problem was that my solution (and any other solution I could think of) always did a complete 90 degree turn which made the lines flow in a way that didn’t look very natural…
Curves angle comparison
Left: The rounded corners method – the middle part of the curve is always completely vertical.
Right: The more natural way – the angle depends on the height and width of the curve
So, obviously, I went into a short denial phase (maybe it'd still be good enough?), followed by me doubting my value as a developer, and finally conceding defeat, remembering I had promised my colleague I would check out the list of JavaScript libraries he sent me.

SVG: A New Hope

So I started looking through the list of libraries my colleague suggested, and then some. Most of them could be put in one of two categories: those that were slightly too specific and for a use case we didn't need (we didn't need it to automatically lay out a graph in an optimal way), and those that were on the verge of being too customizable (I didn't want to include a huge library full of features I’d need to turn off, from mouse-wheel-zoom to drag-and-drop reordering of items).
While I was looking for more blog posts and articles for ideas, I stumbled upon this link: https://javascript.info/bezier-curve. Since the article was kind of math-y (and I'm not really a math person), I skimmed the page for code examples I could use or screenshots that would show me if it fit our use case. Then I saw this curve that looked exactly like what I wanted, so I fired up my developer toolbar, hoping to find they’d somehow made it with CSS and half expecting to be disappointed by it being a still image. Instead, I found that it was completely SVG, and that the example even had interactive handles so you could drag the dots around and play with the angles (although I liked the angles just the way they initially had them).
A picture of the bezier curve with the developers-tools open
So then I started thinking – maybe I can use SVG? But SVG is complicated, and when I’d looked at it before (copying or updating SVG assets we get from our designer) it had all these random letters and numbers one right after the other that I couldn't make head nor tail of. Maybe this one would be easier?
I started dragging the handles on the example around and trying to figure out if I could understand how they changed the SVG. In the SVG I found only one "path" that had stroke="red" so I figured that was the actual line I was looking for:
Gif of dragging the handles on the bezier and seeing the changes in the developer tools
Looking at the <path>'s attributes, I could see id, stroke, fill, and stroke-width, all of which looked normal and pretty self-explanatory. The only weird attribute was the "d" one. When I moved the first knob left and right, the only thing that changed was the very first number in the "d" attribute. When I moved it up and down, only the second number changed. I kept playing around with the knobs, and the numbers appeared to all be pairs of coordinates of the starting point, first knob, second knob, and end of the curve, and it looked like "MX,Y CX,Y X,Y X,Y".
The numbers seemed clear enough. But what about the letters “M” and ”C”? Where were you supposed to put them? Now that I had something to search for, I quickly found this MDN article that told me what each letter means – specifically, M means "move to" or in this case (since it comes at the beginning) "start here", and C is for making Bezier curves. So this unintelligible line of letters and numbers turned to "move to X/Y, from there create a curve through X/Y and X/Y, and finish at X/Y".
Now that I knew how these basic shapes are made, suddenly it wasn’t as scary to create my own path. Since we wanted the curves to be from the left edge of the drawing to the right edge, we could put that in the above "equation" and get:
<path d="M0,height1 ChalfWidth,height1 halfWidth,height2 width,height2">
(At that point I was doing a tiny dance in my head for managing to actually write by myself and from scratch the mysterious string of numbers and letters that had always seemed inscrutable when I saw them in SVG files)
The next step was layering those connector paths, and with some CSS styling I was able to get a finished product that looked just like the design mock-up:
GIF of the finished product
The page in action
Finished product with developer tools open
Behind the scenes
Aaaand, push to production! :)

The moral of the story

I now know that not everything can be achieved just with HTML+CSS (I stand corrected 😳). Next time I need to implement a design with some more complex graphics, I know I have another tool in my arsenal I can use. I know I’ve barely scratched the surface of SVG’s capabilities, but now I know where to look and what to look for in the unlikely case CSS fails me again. 😋

Potato

Thumbnail courtesy of Fabien Bazanegue
We’re Hiring!
Oribi is growing,
come join our amazing team :)
Check out our Careers Page