SVG is weird. It's also essential.

It doesn't take long to realize that most D3 projects use SVG as their output medium. At the same time, "regular" web developers rarely work directly with SVG, making it a common stumbling block for people new to D3. Even if you've adopted SVG icons or images in an app, you're probably not familiar with the inner workings of the format or some of the quirks that come with using it.

The same, but different

In some ways, SVG elements are no different than "traditional" DOM element types like divs and spans. SVG elements are containers with no visual appearance of their own by default, just like a div. They can be given dimensions, padding, background color, etc., just like a div. So far, so good.

Unlike a div, however, only certain elements can be nested inside an SVG element. For example, the following markup will not render anything visible to the page.

<svg><button>Hi</button></svg>

This markup will though, because SVG have a default size of 300x150 pixels. Once again, unlike a div.

<svg style="background-color: blue"></svg>

SVG can also blur the line between styling and markup at times. We could change the size of our SVG element like this, just like a div.

<svg style="width: 600px;
            height: 400px;
            background-color: blue;">
</svg>

But we could also do it like this.

<svg width="600" height="400"
     style="background-color: blue">
</svg>

So with SVG elements (and their children) some things can be specified in markup OR as a style.

When those things are defined in markup, pixels are the implicit unit. You can override this by specifying the units (width="20em") but by default everything is pixels.

My kids are special!

So we've seen that buttons are not welcome as SVG children. What then, pray tell, are we allowed to use? Well, the primary types of children are basic shapes like rect, circle, ellipse, and line. Kind of boring, right?

On its own, the type of children supported by SVG is definitely not interesting. Where things get interesting is instead the myriad ways they can be arranged, layered, styled, and animated.

That first quality, arrangement, is where we'll start. While normal DOM elements are laid out by the browser to prevent overlap and ensure each element's size is respected, no such layout happens inside an SVG element. By default, everything is rendered at 0 x 0, or the top left corner.

Take this markup as an example.

<svg width="600" height="400">
  <rect width="200" height="200"></rect>
  <circle cx="100" cy="100" r="100"></circle>
</svg>

And this CSS.

/* fill is like background-color for SVG shapes */
circle {
  fill: red;
}

If the shapes were laid out like normal DOM elements we'd see something like this, assuming rect is a block level element.

Imgur

But instead we see this!

Imgur

Yea, so?

You mean you're not blown away by a circle on top of a square? 😂 (You can play with this enthralling example here.)

I admit, this example is not exciting. In fact, you might even think this seems tedious. You have to explicitly position every element? Yep. Well, it would be tedious if you were creating and positioning every element by hand. Thankfully, D3 has a LOT of APIs for creating and manipulating SVG shapes. (Pssst! This is called foreshadowing.)

And that's not to mention how many visualizations simply wouldn't be possible if some layout engine were preventing the overlap of shapes. Think you could create a bubble chart from divs using nothing but border radius, floats, and margins? My head hurts just thinking about it.

We're obviously just scratching the surface here in the tiniest of ways. Next week we'll look at some more SVG idiosyncracies so we're better equipped to work with this quirky but massively powerful and essential technology.

Happy hacking!