An in-depth SVG tutorial
SVG is an awesome and incredibly powerful image format. This tutorial gives you an overview of SVG by explaining all you need to know in a simple way
- Introduction
- The advantages of SVG
- Your first SVG image
- Using SVG
- SVG Elements
- SVG viewport and viewBox
- Inserting SVG in Web Pages
- Inline SVG using a Data URL
- Styling elements
- Interacting with a SVG with CSS or JavaScript
- SVG vs Canvas API
- SVG Symbols
- Validate an SVG
- Should I include the
xmlnsattribute? - Should I worry about browser support?
Introduction
Despite being standardized in the early 2000s, SVG (a shorthand for Scalable Vector Graphics) is a hot topic these days.
SVG has been penalized for quite a few years by the poor browser support (most notably IE).
I found this quote from a 2011 book: “at the time of writing, direct embedding of SVG into HTML works only in the very newest browsers”. 7 years ago, this is now a thing of the past, and we can use SVG images safely.
Today we can use SVG images safely, unless you have a lot of users with IE8 and below, or with older Android devices. In this case, fallbacks exist.

Some part of the success of SVG is due to the variety of screen displays we must support, at different resolutions and sizes. A perfect task for SVG.
Also, the rapid decline of Flash in the last few years led to a renewed interest in SVG, which is great for a lot of things that Flash did in the past.
SVG is a vector image file format. This makes them very different than image format such as PNG, GIF or JPG, which are raster image file formats.
The advantages of SVG
SVG images, thanks to being vector images, can infinitely scale and not have any issue in image quality degradation. How so? Because SVG images are built using XML markup, and the browser prints them by plotting each point and line, rather than filling some space with pre-defined pixels. This ensures SVG images can adapt to different screen sizes and resolutions, even ones that have yet to be invented.
Thanks to being defined in XML, SVG images are much more flexible than JPG or PNG images, and** we can use CSS and JavaScript to interact with them**. SVG images can even contain CSS and JavaScript.
SVG images can render vector-style images a lot smaller than other formats, and are mainly used on logos and illustrations. Another huge use case is icons. Once domain of Icon Fonts like FontAwesome, now designers prefer using SVG images because they are smaller and they allow to have multi-color icons.
SVG is easy to animate, which is a very cool topic.
SVG provides some image editing effects, like masking and clipping, applying filters, and more.
SVG are just text, and as such it can be efficiently compressed using GZip.
Your first SVG image
SVG images are defined using XML. This means that SVG will look very familiar if you are proficient in HTML, except rather than having tags that are suited for document construction (like p, article, footer, aside) in SVG we have the building blocks of vector images: path, rect, line and so on.
This is an example SVG image:
<svg width="10" height="10">
<rect x="0" y="0" width="10" height="10" fill="blue" />
</svg>
Notice how it’s very easy to read and understand how the image will look like: it’s a simple blue rectangle of 10x10 pixels (the default unit).
Most of the times you won’t have to edit the SVG code, but you will use tools like Sketch or Figma or any other vector graphics tool to create the image, and export it as SVG.
The current version of SVG is 1.1, and SVG 2.0 is under development.
Using SVG
SVG images can be displayed by the browser by including them in a img tag:
<img src="image.svg" alt="My SVG image" />
just like you would do for other pixel-based image formats:
<img src="image.png" alt="My PNG image" />
<img src="image.jpg" alt="My JPG image" />
<img src="image.gif" alt="My GIF image" />
<img src="image.webp" alt="My WebP image" />
In addition, pretty uniquely, SVG they can be directly included in the HTML page:
<!doctype html>
<html>
<head>
<title>A page</title>
</head>
<body>
<svg width="10" height="10">
<rect x="0" y="0" width="10" height="10" fill="blue" />
</svg>
</body>
</html>
Please note that HTML5 and XHTML require a different syntax for inline SVG images. Luckily XHTML is a thing of the past, as it was more complex than necessary, but it’s worth knowing in case you still need to work on XHTML pages.
The ability to inline SVG in HTML makes this format a unicorn in the scene, as other images can’t do this, and must be fetched by opening a separate request for each one.
SVG Elements
In the example above you saw the usage of the rect element. SVG has a lot of different elements.
The most used ones are
text: creates a text elementcircle: creates a circlerect: creates a rectangleline: creates a linepath: create a path between two pointstextPath: create a path between two points, and a linked text elementpolygon: allows to create any kind of polygong: groups separate elements
Coordinates start at 0,0 at the top-left of the drawing area, and extend from left to right for
x, from top to bottom fory.
The images you see reflect the code shown above. Using the Browser DevTools you can inspect and change them.
text
The text element adds text. The text can be selected using the mouse. x and y define the starting point of the text
<svg>
<text x="5" y="30">A nice rectangle</text>
</svg>

circle
Define a circle. cx and cy are the center coordinates, and r is the radius. fill is a common attribute and represents the figure color.
<svg>
<circle cx="50" cy="50" r="50" fill="#529fca" />
</svg>

rect
Defines a rectangle. x, y are the starting coordinates, width and height are self-explanatory.
<svg>
<rect x="0" y="0" width="100" height="100" fill="#529fca" />
</svg>

line
x1 and y1 define the starting coordinates. x2 and y2 define the ending coordinates. stroke is a common attribute and represents the line color.
<svg>
<line x1="0" y1="0" x2="100" y2="100" stroke="#529fca" />
</svg>

path
A path is a sequence of lines and curves. It’s the most powerful tool to draw using SVG, and as such it’s the most complex.
d contains the directions commands. These commands start with the command name, and a set of coordinates:
Mmeans Move, it accepts a set of coordinates x, yLmeans Line, it accepts a set of coordinates x, y to draw the line toHis an Horizontal Line, it only accept an x coordinateVis a Vertical Line, it only accept an y coordinateZmeans Close Path, puts a line back to the startAmeans Arch, it needs a whole tutorial on its ownQis a quadratic Bezier curve, again it needs a whole tutorial on its own
<svg height="300" width="300">
<path
d="M 100 100 L 200 200 H 10 V 40 H 70"
fill="#59fa81"
stroke="#d85b49"
stroke-width="3"
/>
</svg>

textPath
Adds a text along the shape of a path element.
<svg
viewBox="0 0 1000 600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<path id="MyPath" d="M 20 40 Q 260 240 400 500" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="#59fa81" />
<text font-family="Courier New" font-size="42.5">
<textPath xlink:href="#MyPath">Wow such a nice SVG tut</textPath>
</text>
</svg>

polygon
Draw any random polygon with polygon. points represents a set of x, y coordinates the polygon should link:
<svg>
<polygon points="9.9, 1.1, 3.3, 21.78, 19.8, 8.58, 0, 8.58, 16.5, 21.78" />
</svg>

g
Using the g element you can group multiple elements:
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="100" fill="#529fca" />
<g id="my-group">
<rect x="0" y="100" width="100" height="100" fill="#59fa81" />
<rect x="100" y="0" width="100" height="100" fill="#ad4a3d" />
</g>
</svg>

SVG viewport and viewBox
The size of an SVG relative to its container is set by the width and height attributes of the svg element. Those units default to pixels, but you can use any other usual unit like % or em. This is the viewport.
Generally “container” means the browser window, but a
svgelement can contain othersvgelements, in that case the container is the parentsvg.
An important attribute is viewBox. It lets you define a new coordinates system inside the SVG canvas.
Say you have a simple circle, in a 200x200px SVG:
<svg width="200" height="200">
<circle cx="100" cy="100" r="100" fill="#529fca" />
</svg>

By specifying a viewBox you can choose to only show a portion of this SVG. For example you can start at point 0, 0 and only show a 100x100px canvas:
<svg width="200" height="200" viewBox="0 0 100 100">
<circle cx="100" cy="100" r="100" fill="#529fca" />
</svg>

starting at 100, 100 you will see another portion, the bottom right half of the circle:
<svg width="200" height="200" viewBox="100 100 100 100">
<circle cx="100" cy="100" r="100" fill="#529fca" />
</svg>

A great way to visualize this is to imagine Google Maps being a gigantic SVG image, and your browser is a viewBox as big as the window size. When you move around, the viewBox changes its starting point (x, y) coordinates, and when you resize the window, you change the width and height of the viewBox.
Inserting SVG in Web Pages
There are various ways to add SVG to a webpage.
The most common ones are:
- with an
imgtag - with the CSS
background-imageproperty - inline in the HTML
- with an
object,iframeorembedtag
See all these examples live on Glitch: https://glitch.com/edit/#!/flavio-svg-loading-ways
With an img tag
<img src="flag.svg" alt="Flag" />
With the CSS background-image property
<style>
.svg-background {
background-image: url(flag.svg);
height: 200px;
width: 300px;
}
</style>
<div class="svg-background"></div>
Inline in the HTML
<svg
width="300"
height="200"
viewBox="0 0 300 200"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<title>Italian Flag</title>
<desc>By Flavio Copes https://flaviocopes.com</desc>
<g id="flag">
<rect fill="green" x="0" y="0" width="100" height="200"></rect>
<rect fill="white" x="100" y="0" width="100" height="200"></rect>
<rect fill="red" x="200" y="0" width="100" height="200"></rect>
</g>
</svg>
With an object, iframe or embed tag
<object data="flag.svg" type="image/svg+xml"></object>
<iframe src="flag.svg" frameborder="0"></iframe>
<embed src="flag.svg" type="" />
Using embed you have the option to get the SVG document from the parent document using
document.getElementById('my-svg-embed').getSVGDocument()
and from inside the SVG you can reference the parent document with:
window.parent.document
Inline SVG using a Data URL
You can use any of the above examples combined with Data URLs to inline the SVG in the HTML:
<img src="data:image/svg+xml;<DATA>" alt="Flag" />
<object data="data:image/svg+xml;<DATA>" type="image/svg+xml"></object>
<iframe data="data:image/svg+xml;<DATA>" frameborder="0"></iframe>
and in CSS too:
.svg-background {
background-image: url('data:image/svg+xml;<DATA>');
}
Just change <DATA> with the appropriate Data URL.
Styling elements
Any SVG element can accept a style attribute, just like HTML tags.
Not all CSS properties work as you would expect, due to the SVG nature. For example to change the color of a text element, use fill instead of color.
<svg>
<text x="5" y="30" style="fill: green">A nice text</text>
</svg>
<svg>
<text x="5" y="70" style="fill: green; font-family: Courier New">
A nice text
</text>
</svg>
You can use fill as an element attribute as well, as you saw before:
<svg>
<text x="5" y="70" fill="green">A nice text</text>
</svg>
Other common properties are
fill-opacity, background color opacitystroke, defines the border colorstroke-width, sets the width of the border
CSS can target SVG elements like you would target HTML tags:
rect {
fill: red;
}
circle {
fill: blue;
}
Interacting with a SVG with CSS or JavaScript
SVG images can be styled using CSS, or scripted with JavaScript, in those cases:
- when the SVG is inlined in the HTML
- when the image is loaded through
object,embedoriframetags
but (⚠️ depending on the browser implementation) they must be loaded from the same domain (and protocol), due to the same-origin policy.
iframe needs to be explicitly sized, otherwise the content is cropped, while object and embed resize to fit their content.
If the SVG is loaded using a img tag, or through CSS as a background, independently of the origin:
- CSS and JavaScript cannot interact with it
- JavaScript contained in the SVG is disabled
- External resources like images, stylesheets, scripts, fonts cannot be loaded
in detail
| Feature | Inline SVG | object/embed/iframe | img |
|---|---|---|---|
| Can interact with the user | ✅ | ✅ | ✅ |
| Supports animations | ✅ | ✅ | ✅ |
| Can run its own JavaScript | ✅ | ✅ | 👎🏼 |
| Can be scripted from outside | ✅ | 👎🏼 | 👎🏼 |
Inline SVG images are definitely the most powerful and flexible, and it’s the only way to perform certain operations with SVG.
If you want to do any interaction with the SVG with your scripts, it must be loaded inline in the HTML.
Loading an SVG in an img, object or embed works if you don’t need to interact with it, just show it in the page, and it’s especially convenient if you reuse SVG images in different pages, or the SVG size is quite big.
CSS inside SVG
Add the CSS in a CDATA:
<svg>
<style>
<![CDATA[
#my-rect { fill: blue; }
]]>
</style>
<rect id="my-rect" x="0" y="0" width="10" height="10" />
</svg>
An SVG file can also include an external style sheet:
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/css" href="style.css"?>
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width=".."
height=".."
viewBox=".."
>
<rect id="my-rect" x="0" y="0" width="10" height="10" />
</svg>
JavaScript inside SVG
You can put the JavaScript first, and wrap in in a load event to execute it when the page is fully loaded and the SVG is inserted in the DOM:
<svg>
<script>
<![CDATA[ window.addEventListener("load", () => { //... }, false) ]]>
</script>
<rect x="0" y="0" width="10" height="10" fill="blue" />
</svg>
or you can avoid adding an event listener if you put the JS at the end of the other SVG code, to make sure the JavaScript runs when the SVG is present in the page:
<svg>
<rect x="0" y="0" width="10" height="10" fill="blue" />
<script>
<![CDATA[ //... ]]>
</script>
</svg>
SVG elements, just like html tags, can have id and class attributes, so we can use the Selectors API to reference them:
<svg>
<rect
x="0"
y="0"
width="10"
height="10"
fill="blue"
id="my-rect"
class="a-rect"
/>
<script>
<![CDATA[ console.log(document.getElementsByTagName('rect'))
console.log(document.getElementById('my-rect'))
console.log(document.querySelector('.a-rect'))
console.log(document.querySelectorAll('.a-rect')) ]]>
</script>
</svg>
Check out this Glitch https://glitch.com/edit/#!/flaviocopes-svg-script for an example of this functionality.
JavaScript outside the SVG
If you can interact with the SVG (the SVG is inline in the HTML), you can change any SVG attribute using JavaScript, for example:
document.getElementById('my-svg-rect').setAttribute('fill', 'black')
or really do any other DOM manipulation you want.
CSS outside the SVG
You can change any styling of the SVG image using CSS.
SVG attributes can be easily overwritten in CSS, and they have a lower priority over CSS. They do not behave like inline CSS, which has higher priority.
<style>
#my-rect {
fill: red;
}
</style>
<svg>
<rect x="0" y="0" width="10" height="10" fill="blue" id="my-rect" />
</svg>
SVG vs Canvas API
The Canvas API is a great addition to the Web Platform, and it has similar browser support as SVG. The main (and big) difference with SVG is that Canvas is not vector based, but rather pixel based, so
- it has the same scaling issues as pixel-based PNG, JPG and GIF image formats
- it makes it impossible to edit a Canvas image using CSS or JavaScript like you can do with SVG
SVG Symbols
Symbols let you define an SVG image once, and reuse it in multiple places. This is a great help if you need to reuse an image, and maybe just change a bit some of its properties.
You do so by adding a symbol element and assigning an id attribute:
<svg class="hidden">
<symbol id="rectangle" viewBox="0 0 20 20">
<rect x="0" y="0" width="300" height="300" fill="rgb(255,159,0)" />
</symbol>
</svg>
<svg>
<use xlink:href="#rectangle" href="#rectangle" />
</svg>
<svg>
<use xlink:href="#rectangle" href="#rectangle" />
</svg>
(xlink:href is for Safari support, even if it’s a deprecated attribute)
This starts to give an idea of the power of SVG.
If you want to style those 2 rectangles differently, for example using a different color for each? You can use CSS Variables.
<svg class="hidden">
<symbol id="rectangle" viewBox="0 0 20 20">
<rect x="0" y="0" width="300" height="300" fill="var(--color)" />
</symbol>
</svg>
<svg class="blue">
<use xlink:href="#rectangle" href="#rectangle" />
</svg>
<svg class="red">
<use xlink:href="#rectangle" href="#rectangle" />
</svg>
<style>
svg.red {
--color: red;
}
svg.blue {
--color: blue;
}
</style>
See my Glitch playground on SVG symbols.
Validate an SVG
An SVG file, being XML, can be written in an invalid format, and some services or apps might not accept an invalid SVG file.
SVG can be validated using the W3C Validator.
Should I include the xmlns attribute?
Sometimes an svg is defined as
<svg>...</svg>
sometimes as
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">...</svg>
This second form is XHTML. It can also be used with HTML5 (documents with <!DOCTYPE html>) but in this case the first form is simpler.
Should I worry about browser support?
Today SVG is supported by the vast majority of user’s browsers.
You can still check for missing support using libraries like Modernizr, and provide a fallback:
if (!Modernizr.svg) {
document.querySelector('.my-svg').setAttribute('src', 'images/logo.png')
} download all my books for free
- javascript handbook
- typescript handbook
- css handbook
- node.js handbook
- astro handbook
- html handbook
- next.js pages router handbook
- alpine.js handbook
- htmx handbook
- react handbook
- sql handbook
- git cheat sheet
- laravel handbook
- express handbook
- swift handbook
- go handbook
- php handbook
- python handbook
- cli handbook
- c handbook
subscribe to my newsletter to get them
Terms: by subscribing to the newsletter you agree the following terms and conditions and privacy policy. The aim of the newsletter is to keep you up to date about new tutorials, new book releases or courses organized by Flavio. If you wish to unsubscribe from the newsletter, you can click the unsubscribe link that's present at the bottom of each email, anytime. I will not communicate/spread/publish or otherwise give away your address. Your email address is the only personal information collected, and it's only collected for the primary purpose of keeping you informed through the newsletter. It's stored in a secure server based in the EU. You can contact Flavio by emailing flavio@flaviocopes.com. These terms and conditions are governed by the laws in force in Italy and you unconditionally submit to the jurisdiction of the courts of Italy.