Learning SVG - the long way

Nuh

Scalable Vector Graphics - SVG

As one person described it, “SVG is not just another type of image, it is also a language and it is to graphics what html is to websites”.

Motivation

I had long been fascinated by patterns. Every time I saw a well-curated use of patterns or simple graphics, I was moved to try and do it myself. To this end, when I finally heard about Blender being a free alternative to Photoshop, I immediately jumped on it and tried to self-learn and recreate the web’s graphics. Sadly, there were too many moving mechanisms and I got tired of it pretty quickly. I am detail oriented and it was just too much to worry about the imperfections of creating 3D items. That hype died down and I was now back to normal doing non-graphics learning.

Then came a pattern my company created for its backgrounds which fit in so nicely and was very simple, I was very impressed and attributed it to the power of Company - advantage of scale. Sometime later I began to be fascinated by SVG and decided to hand-write SVGs and reproduce patterns I notice in real life. And here we are!

Intro to SVG

To keep it short, SVG is a document model that is also an image format. Both SVG and HTML are subset of XML, and work together. SVG has been supported by almost all browsers for a very long time.

Just as a HTML document is begun / enclosed in a <html> element, SVG document is also enclosed with <svg> but with differing attributes. Let’s inspect an example.

 <svg width="100" height="100" viewBox="0 0 100 200" fill="none" xmlns="http://www.w3.org/2000/svg">
   ...
 </svg>

The width and height are permanent mainstays in an SVG document, they determine the scope/viewport of your SVG image. The xmlns specifies the XML namespace to use. The fill and viewBox are optional. The fill sets the default color for objects inside the SVG and we will talk about the viewBox soon. There are many other attributes that are optional and can be found on MDN.

There is an excellent article by Sara Soueidan on the viewBox here.

Discrete shapes

We will take a look how to draw discrete shapes with examples. First, as the name implies, we wish to look at shapes that have no curves except the circle and arcs. So, this will be lines, composition of lines, rectangles, triangles, n-gons.

Almost all the discrete shapes have specific elements associated with them already. We begin with the rectangle which takes the following syntax

 <svg width="100" height="100" viewBox="0 0 100 200" fill="none" xmlns="http://www.w3.org/2000/svg">
   <rect width="100" height="100" x="50" y="50" rx="20" fill="green" stroke="yellow"/>
 </svg>

The width and height attributes need no explanation and the x and y coordinates simply determine where the rectangles top-left corner should be placed - by default it is on the 0,0 of the viewBox (top-left corner of the canvas). The rx attribute corresponds to rounding off the corners of the rectangle and fill is self-explanatory while stroke is the outline.

One can easily create a square and a circle (using suitable rx value) from a rectangle.

Now on to lines - the syntax looks like this

 <svg width="100" height="100" viewBox="0 0 100 200" fill="none" xmlns="http://www.w3.org/2000/svg">
   <line x1="0" y1="0" x2="20" y2="50" stroke="yellow" stroke-width="4"/>
 </svg>

A line is drawn from the (x1, y1) to (x2, y2). A bit of Cartesian tutorial if you are unfamiliar with it can be found here.

A triangle is now a matter of drawing three lines but there’s a quicker more straightforward way to achieve it via the path element or polyline element. We will first demonstrate with the polyline element. The syntax is

 <svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
   <polyline points="10,10 20,10 15,20 10,10" stroke="orange" stroke-width="2" fill="green"/>
 </svg>

The points of the triangle are entered in a points attribute of the polyline element. The 4th point which is a repeat of the first point is there so that the line is drawn back to the starting point. By default, the polyline element draws a line between points as they are listed.

Now on to polygons and n-gons - the polygon. This is surprisingly no different to the polyline, except that lines are drawn between all points (include line between starting point and endpoint). The syntax is

 <svg width="100" height="100" viewBox="0 0 100 200" fill="none" xmlns="http://www.w3.org/2000/svg">
   <polygon points="10,10 20,10 15,20 10,10" stroke="orange" stroke-width="2" fill="green"/>
 </svg>

The polygon element, despite its name, is useful for drawing any shape that is enclosed by a “fence” or that a line passes through all the points.

Now onto the special case of a circle, ellipse and an arc. The syntax for a circle is as follows

 <svg width="100" height="100" viewBox="0 0 100 200" fill="none" xmlns="http://www.w3.org/2000/svg">
    <circle cx="40" cy="40" r="24" stroke="orange" stroke-width="2" fill="green"/>
 </svg>

Unsurprisingly, the circle element takes as input cx and cy as the circle’s centre (cx, cy) and r as its radius.

The ellipse element is no different except a split of the circle’s radius into directional radii rx (horizontal radius) and ry (vertical radius). Syntax is

 <svg width="100" height="100" viewBox="0 0 100 200" fill="none" xmlns="http://www.w3.org/2000/svg">
    <ellipse cx="40" cy="40" rx="10" ry="20" stroke="orange" stroke-width="2" fill="green"/>
 </svg>

To draw an arc, we will have to use the path element so we will begin with it in our next section on continuous shapes.

Continuous shapes

Top Lessons in Writing SVG

  1. Rendering prioritisation

    You can prioritise what trade-offs to make between speed and quality. Collectively known as rendering hints, color-rendering, text-rendering, image-rendering, shape-rendering all enable respective SVG elements to be rendered with priority on either speed, quality, or where applicable legibility and geometric precision. More can be read here on the spec.

  2. Paint order

    You can specify the order of painting the fill, stroke and marker. It specially has a strong effect when rendering text.

  3. Will-change

    You can tell the user-agent ahead of time if a rendered element is going to change in some way visually and tell what part of it is changing so it can prepare the change beforehand to enable smooth change. E.g. it can anticipate that the element will be transformed.

  4. Styling order

    SVG attempts to be conflict-free with HTML so implements styling as if it were HTML. The only exception is that SVG has presentation attributes, which gives another way of applying styling. However, presentation styling is given low specificity, meaning that it is overridden by any of the CSS styling be it inline css or style scripts. (TODO: investigate if presentation attribute is really lowest specificity/priority)

  5. Cloned styles when using use

    Anything other than direct selectors are not cloned, i.e. class names are ignored. More details here.

Tricks / tips

  1. Paint flashing in DevTools allows you to see if your animation is hardware accelerated or not
  2. Add a transform, backface-visibility or perspective in your styling triggers hardware acceleration
  3. For SMIL hardware acceleration, use animateTransform and set x,y,z values with 0 for z.
Nuh © 2024