Random Musings

O for a muse of fire, that would ascend the brightest heaven of invention!


Making logos with Scalable Vector Graphics

Saturday, 7 Nov 2026 Tags: svg

I have been experimenting with logos for a couple of projects. Once you have a name, or an idea, you can put together some simple shapes pretty quickly.

I used the SVG Viewer as a side-by-side editor, great for quickly trying out ideas, with basic editing functionality. At the end of this article you’ll find a couple more fancy tools.

Scalar Vector Graphics, commonly known as SVG, are a lot of fun to play with, just with a browser and knowing a few basic rules. After the hustle and bustle of the week, it’s very relaxing to sit down, and slap together some images.

Under the hood, it’s an XML based format, with some simple rules for composing more and more complex images.

The very first svg I did was for a logo for my company, probably over a decade ago, and when I wanted to redo it now, I realised I had not made any notes about how this is done, so I had to re-discover it all again.

Inline SVG

The first thing we want to do, is to display an svg within a web page. MDN’s SVG in HTML guide has us covered - it’s just another pair of tags: <svg> ... </svg>, and inside some elements.

Circles

This is about as easy as it can get.

<svg>
  <circle cx="50" cy="50" r="40" fill="orange"/>
</svg>

Squares

Squares are just rectangles where the width and height are equal.

Let’s add a couple of effects, most obviously a nicer orange colour, #ff8000, and rounded corners using the rx attribute. We also introduce the x attribute, which is the x coordinate of the rectangle. These will be used later on for more complex positioning in composite images.

<svg>
  <rect x="120" width="100" height="100" rx="20" fill="#ff8000"/>
</svg>

Polygons

There are probably many ways to do this, here’s two different approaches. The first one, is to specify vertices, and let svg join the dots.

<svg>
  <polygon points="15,90 15,45 50,12 85,45 85,90"
    fill="red"
    stroke="black"
    stroke-width="20"
    stroke-linejoin="round"
  />
</svg>

Instead of directly drawing the polygon, it’s possible to generate a path by specifying the movement of a virtual pen:

<svg>
  <path d="m15 90
           l0 -45
           l35 -33
           l35 33
           l0 45
           z"
    fill="blue"
    stroke="orange"
    stroke-width="20"
    stroke-linejoin="round"
  />
</svg>

Each lowercase command moves the pen from where it currently is, rather than to a fixed spot.

  • m15 90 move to the start point at (15, 90), the bottom-left corner.

Because it’s the first command, there’s nothing yet to be relative to, so it behaves like an absolute location.

  • l0 -45 draw the left wall, going 0 across and 45 up, since negative y means up. The pen is now at (15, 45)

  • l35 -33 draw the left side of the roof, 35 right and 33 up, to the peak at (50, 12)

  • l35 33 draw the right side of the roof, 35 right and 33 down, to (85, 45)

  • l0 45 draw the right wall, 45 down, to (85, 90)

  • z close the shape by drawing the floor back to the start

The two roof lines are mirror images: the only difference is the sign of the y value. The two walls are the same. You can also see that the y values add up to zero (−45 − 33 + 33 + 45 = 0), which shows you’ve ended on the same level as the starting point.

Relative commands make it easy to shift the whole shape. To move the house, change only the starting m15 90, and every other line follows along. With absolute coordinates, you’d have to edit every point manually.

Now we have the basics down, let’s build a composite shape, combining the house, the circle, and a couple of boxes. These will need to sit within a container, so we have a wee detour to the viewBox first.

the viewBox

I think of it as a window that you place over and around your image. This sets up things like a margin, and scaling both within the viewbox, and on the page.

The viewBox specifies the coordinate system our shapes are drawn in. viewBox="0 0 100 100" means “the visible area starts at x=0, y=0 and is 100 units wide and 100 units tall”.

With a viewBox, the browser maps those 100×100 units onto whatever size the SVG is displayed at. If the SVG appears 50 pixels wide or 2000 pixels wide, the drawing shrinks or grows to fit, and it stays sharp because the browser redraws it from the shapes at each size. Without a viewBox, each unit is fixed at one pixel, so the drawing can’t resize, and anything outside the default canvas gets cut off.

The four numbers are the x and y of the top-left corner, then the width and height. Changing them works like moving a camera. viewBox="0 0 50 50" zooms in on just the top-left quarter, showing part of the house at twice the size. viewBox="-10 -10 120 120" would zoom out slightly, adding a margin around everything.

<svg width="150" height="150" viewBox="0 0 100 100">
  <polygon points="15,90 15,45 50,12 85,45 85,90"
    fill="red" stroke="black" stroke-width="20"
    stroke-linejoin="round"/>
</svg>
<svg width="150" height="150" viewBox="0 0 50 50">
  <polygon points="15,90 15,45 50,12 85,45 85,90"
    fill="red" stroke="black" stroke-width="20"
    stroke-linejoin="round"/>
</svg>

Composition with path

The canvas is a viewBox="0 0 200 200", a 200×200 grid, within which we will position four 100x100 quadrants. Each shape sits inside its own quadrant with a margin of about 15 on each side.

There is just one that draws four separate shapes. The key idea is that every M (move) lifts the pen and starts a new shape, so the d attribute holds four subpaths that all share the same fill and stroke, and within each shape we use relative positioning. This means that each square is the same movements, just from a different starting position.

The commands used are either Uppercase for absolute positioning, or lowercase for relative positioning:

  • M moves without drawing
  • L draws a line to a point
  • H and V draw horizontal and vertical lines
  • A draws an arc
  • Z closes the shape

I’ve taken a few abnormal liberties with the layout, so it’s easier to read and reason about, the # comments are not valid syntax:

<svg viewBox="0 0 200 200">
  <path
    fill="#4a7bd0"
    stroke="#4a7bd0"
    stroke-width="8"
    stroke-linejoin="round"
    d="M15 90                 # house: start bottom-left (15,90), absolute
         v -45                # left wall: up 45
         l35 -33              # roof left: 35 right, 33 up to peak (50,12)
         l35  33              # roof right: 35 right, 33 down to (85,45)
         v45                  # right wall: down 45
       z                      # floor: close back to start
       M115 20                # top-right square: start top-left (115,20)
         h  70                # top edge: right 70
         v  70                # right edge: down 70
         h -70                # bottom edge: left 70
       z                      # left edge: close back to start
       M15 115                # bottom-left square: start top-left (15,115)
         h  70                # top edge: right 70
         v  70                # right edge: down 70
         h -70                # bottom edge: left 70
       z                      # left edge: close back to start
       M115 150               # circle: start at left edge (115,150)
         a35 35 0 0 0 70 0    # bottom half: arc 70 right to (185,150)
         a35 35 0 0 0 -70 0   # top half: arc 70 left back to start
      z"                      # close the circle
    />

All four shapes inherit the same fill, stroke and stroke-width. Because the stroke is the same colour as the fill, it doesn’t show as an outline. It just extends each shape by 4 units (half of 8) on every side, and stroke-linejoin="round" turns every corner into a curve with a radius of 4.

Arcs

The first a 35 35 ... draws a half-circle arc to the right edge, and the second a 35 35 ... draws the other half back to the start. Two arcs are needed because a single arc can’t start and end at the same point, so we need a pair to make a full circle.

A35 35 0 0 0 185 150 has seven numbers:

  • 35 35 is the x and y radius, equal makes it circular, vs elliptical
  • 0 is the rotation, which only matters for ellipses
  • 0 0 are two flags, the first says whether to take the large or small way around, and the second says whether to go clockwise or not
  • 185 150 is where the arc ends

All together we have this rather satisfying collection, vaguely reminiscint of one of those childrens’ block games, where you hope people don’t try to fit all the shapes through the large square hole, but actually match them up correctly.

The Final Cut

We are close. So close, but I want just one more change. I want each element to be in a different colour. How hard can that be? Well, the big thing is that we need to split our single d attribute out into multiple ones, so we can apply individual colours.

Let’s replace our hard-won hand-specified shapes, with circle and rect, and polygon again. This will make it a lot more readable.

Then, welcome to our final trick, currentColor, which lets us reset the color attribute during each path element:

<svg viewBox="0 0 200 200"
     fill="currentColor"
     stroke="currentColor"
     stroke-width="20"
     stroke-linejoin="round">
  <polygon color="#2e7d5b" points="15,90 15,45 50,12 85,45 85,90"/>
  <rect    color="#e0a030" x="115" y="20"  width="70" height="70"/>
  <rect    color="#d0504a" x="15"  y="115" width="70" height="70"/>
  <circle  color="#17262e" cx="150" cy="150" r="35"/>
</svg>

Just One More Thing

OK, ok, this is a long post already, but.. I just needed to have the last word. Actually, a word. On my picture. Let’s slap the words i❤️svg on the end. For this we need to introduce the unsurprisingly named text element, and finagle a bit its x,y, and font-size attributes until it lines up nicely with the rest of things.

To make the layout a bit less confusing, we’ll group the logo itself, by wrapping it in <g>.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1500 200">
  <g fill="currentColor"
     stroke="currentColor"
     stroke-width="20"
     stroke-linejoin="round">
    <polygon color="#2e7d5b" points="15,90 15,45 50,12 85,45 85,90"/>
    <rect    color="#e0a030" x="115" y="20"  width="70" height="70"/>
    <rect    color="#d0504a" x="15"  y="115" width="70" height="70"/>
    <circle  color="#17262e" cx="150" cy="150" r="35"/>
  </g>

  <text x="240" y="160"
        font-family="'Young Serif', serif"
        font-size="180"
        fill="#17262e">i❤️svg</text>
</svg>

Due to some of the complexities of blog software, the above svg doesn’t quite render in the browser as we wanted, so.. yes.. just one final trick.

We convert the whole thing into an img with src="data:image/svg+xml,.... inlined and URL-encoded. And voila!

i love svg

I think that’s easily enough for today.

Tools

If you’re stuck, there are a couple more excellent web-based tools that you can use, experimenting with the transformations in a browser, and then exporting to SVG to see what the tools do.

  • SVG Colour Picker does what it says on the tin

  • Gravit Design is a full SVG editor in a browser, allowing import, export, editing, and conversion to PNG as well

On the command line, I used resvg and usvg to play with various transformations, ultimately using them to automate generating various formats, colours, and sizes, of my images from first principles.

Finally, no SVG tool discussion would be complete without mentioning InkScape a powerful and free desktop design tool, available in every distro known today.