Making logos with Scalable Vector Graphics
Saturday, 7 Nov 2026
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 90move 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 -45draw the left wall, going 0 across and 45 up, since negative y means up. The pen is now at (15, 45) -
l35 -33draw the left side of the roof, 35 right and 33 up, to the peak at (50, 12) -
l35 33draw the right side of the roof, 35 right and 33 down, to (85, 45) -
l0 45draw the right wall, 45 down, to (85, 90) -
zclose 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
The commands used are either Uppercase for absolute positioning, or lowercase for relative positioning:
Mmoves without drawingLdraws a line to a pointHandVdraw horizontal and vertical linesAdraws an arcZcloses 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 35is the x and y radius, equal makes it circular, vs elliptical0is the rotation, which only matters for ellipses0 0are two flags, the first says whether to take the large or small way around, and the second says whether to go clockwise or not185 150is 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 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.