Toolmingo
Guides8 min read

What Is SVG? The Scalable Vector Graphics Format Explained

Learn what SVG is, how it differs from PNG and JPG, when to use it, and how to create, parse, and optimize SVG files in JavaScript, Python, Go, and PHP.

What Is SVG? The Scalable Vector Graphics Format Explained

SVG (Scalable Vector Graphics) is an XML-based image format that describes graphics using mathematical shapes rather than pixels. Because SVG is resolution-independent, a single file looks sharp on a mobile screen, a 4K monitor, or a billboard — with zero quality loss at any size.

SVG is the native format for icons, logos, illustrations, charts, and UI graphics on the modern web. Every major browser renders SVG natively, and it can be inlined directly into HTML.


SVG vs Raster Formats (PNG, JPG, WebP)

SVG PNG JPG WebP
Encoding Vector (math) Raster (pixels) Raster (pixels) Raster (pixels)
Scales without blur ✅ Yes ❌ No ❌ No ❌ No
Transparency ✅ Yes ✅ Yes ❌ No ✅ Yes
Animation ✅ Built-in (SMIL/CSS) ❌ No ❌ No ❌ No
Editable with CSS/JS ✅ Yes ❌ No ❌ No ❌ No
Best for Icons, logos, charts Screenshots, UI Photos Web photos
Worst for Photos, complex images Large illustrations Text, sharp edges Vector art

Rule of thumb: use SVG for anything you draw (icons, logos, diagrams, charts); use raster formats for photographs and complex textures.


SVG File Structure

An SVG file is plain XML. Open any .svg in a text editor and you'll see something like this:

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

  <!-- A red circle -->
  <circle cx="50" cy="50" r="40"
          fill="red" stroke="black" stroke-width="2" />

  <!-- A blue rectangle -->
  <rect x="10" y="60" width="30" height="20"
        fill="blue" opacity="0.5" />

  <!-- Text -->
  <text x="50" y="95" text-anchor="middle"
        font-size="10" fill="white">Hello</text>
</svg>

Core SVG Elements

Element Purpose Key attributes
<svg> Root container width, height, viewBox
<rect> Rectangle x, y, width, height, rx (rounded corners)
<circle> Circle cx, cy, r
<ellipse> Ellipse cx, cy, rx, ry
<line> Straight line x1, y1, x2, y2
<polyline> Open polygon points
<polygon> Closed polygon points
<path> Arbitrary shape d (path data — M/L/C/A/Z commands)
<text> Text x, y, font-size, fill
<g> Group id, transform
<use> Reuse element href
<defs> + <symbol> Define reusable assets

The viewBox Attribute — Why It Matters

viewBox="minX minY width height" defines the internal coordinate system. The outer width/height attributes set the rendered size in the browser.

<!-- 24×24 coordinate space, rendered at 48×48px (2× sharp on retina) -->
<svg viewBox="0 0 24 24" width="48" height="48">
  <path d="M12 2L2 22h20L12 2z" />
</svg>

Omit width/height and the SVG will scale to fill its CSS container — a common technique for responsive icons.


Generating SVG Programmatically

JavaScript (Browser + Node)

Browser — modify the live DOM:

const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', '0 0 100 100');
svg.setAttribute('width', '100');
svg.setAttribute('height', '100');

const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', '50');
circle.setAttribute('cy', '50');
circle.setAttribute('r', '40');
circle.setAttribute('fill', 'steelblue');

svg.appendChild(circle);
document.body.appendChild(svg);

Node.js — generate SVG string:

function makeBadge(label, value) {
  return `<svg xmlns="http://www.w3.org/2000/svg" width="120" height="20" viewBox="0 0 120 20">
  <rect width="60" height="20" fill="#555"/>
  <rect x="60" width="60" height="20" fill="#4c1"/>
  <text x="30" y="14" fill="#fff" font-size="11"
        text-anchor="middle" font-family="sans-serif">${label}</text>
  <text x="90" y="14" fill="#fff" font-size="11"
        text-anchor="middle" font-family="sans-serif">${value}</text>
</svg>`;
}

const fs = require('fs');
fs.writeFileSync('badge.svg', makeBadge('build', 'passing'));

Python

# pip install svgwrite
import svgwrite

def make_chart(data: list[int], filename: str = "chart.svg") -> None:
    """Generate a simple bar chart as SVG."""
    width, height = 300, 200
    bar_width = width / len(data)
    max_val = max(data)

    dwg = svgwrite.Drawing(filename, size=(width, height))
    dwg.add(dwg.rect((0, 0), (width, height), fill="white", stroke="black"))

    for i, val in enumerate(data):
        bar_h = (val / max_val) * (height - 20)
        x = i * bar_width
        y = height - bar_h
        dwg.add(dwg.rect(
            insert=(x + 2, y),
            size=(bar_width - 4, bar_h),
            fill="steelblue"
        ))
        dwg.add(dwg.text(
            str(val),
            insert=(x + bar_width / 2, y - 2),
            text_anchor="middle",
            font_size="10px",
            fill="black"
        ))

    dwg.save()

make_chart([40, 80, 60, 100, 55, 75])

Parse an existing SVG (stdlib only):

import xml.etree.ElementTree as ET

tree = ET.parse('icon.svg')
root = tree.getroot()
ns = {'svg': 'http://www.w3.org/2000/svg'}

# Find all circles
for circle in root.findall('.//svg:circle', ns):
    print(circle.attrib)   # {'cx': '50', 'cy': '50', 'r': '40', ...}

Go

package main

import (
    "fmt"
    "os"
    "text/template"
)

type BarChart struct {
    Width, Height int
    Bars          []Bar
}

type Bar struct {
    X, Y, W, H float64
    Label       string
    Fill        string
}

const svgTmpl = `<svg xmlns="http://www.w3.org/2000/svg"
     width="{{.Width}}" height="{{.Height}}"
     viewBox="0 0 {{.Width}} {{.Height}}">
  <rect width="{{.Width}}" height="{{.Height}}" fill="white" stroke="#ccc"/>
  {{- range .Bars}}
  <rect x="{{.X}}" y="{{.Y}}" width="{{.W}}" height="{{.H}}" fill="{{.Fill}}"/>
  <text x="{{printf "%.1f" (add .X (div .W 2.0))}}"
        y="{{printf "%.1f" (sub .Y 4.0)}}"
        text-anchor="middle" font-size="10" fill="#333">{{.Label}}</text>
  {{- end}}
</svg>`

func main() {
    tmpl := template.Must(template.New("svg").Funcs(template.FuncMap{
        "add": func(a, b float64) float64 { return a + b },
        "sub": func(a, b float64) float64 { return a - b },
        "div": func(a, b float64) float64 { return a / b },
    }).Parse(svgTmpl))

    chart := BarChart{
        Width:  300,
        Height: 200,
        Bars: []Bar{
            {X: 10, Y: 60, W: 60, H: 130, Label: "Jan", Fill: "steelblue"},
            {X: 80, Y: 40, W: 60, H: 150, Label: "Feb", Fill: "tomato"},
            {X: 150, Y: 80, W: 60, H: 110, Label: "Mar", Fill: "seagreen"},
        },
    }

    f, _ := os.Create("chart.svg")
    defer f.Close()
    tmpl.Execute(f, chart)
    fmt.Println("chart.svg written")
}

PHP

<?php
function makeSvgCircle(float $cx, float $cy, float $r, string $fill): string {
    $cx = htmlspecialchars((string)$cx, ENT_XML1);
    $cy = htmlspecialchars((string)$cy, ENT_XML1);
    $r  = htmlspecialchars((string)$r,  ENT_XML1);
    $fill = htmlspecialchars($fill, ENT_XML1);

    return <<<SVG
<svg xmlns="http://www.w3.org/2000/svg"
     width="200" height="200"
     viewBox="0 0 200 200">
  <circle cx="{$cx}" cy="{$cy}" r="{$r}"
          fill="{$fill}" stroke="black" stroke-width="2"/>
</svg>
SVG;
}

// Write to file
$svg = makeSvgCircle(100, 100, 80, 'coral');
file_put_contents('circle.svg', $svg);

// Parse SVG with SimpleXML
$xml = simplexml_load_file('circle.svg');
$xml->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
$circles = $xml->xpath('//svg:circle');
foreach ($circles as $c) {
    echo "Circle: cx={$c['cx']} cy={$c['cy']} r={$c['r']}\n";
}

Optimizing SVG Files

SVGs exported from Illustrator, Figma, or Inkscape carry a lot of metadata, editor comments, and redundant attributes. Optimization typically shrinks file size by 30–70%.

SVGO (Node.js):

npx svgo input.svg -o output.svg
# Or optimize all SVGs in a directory:
npx svgo --folder ./icons

Key things SVGO removes:

  • Editor metadata (<sodipodi:*>, <inkscape:*>)
  • Comments and <!-- -->
  • Redundant id attributes
  • Default attribute values (e.g., fill="black")
  • Empty groups <g></g>
  • Precision: rounds 0.999999991

Python (scour):

pip install scour
scour -i input.svg -o output.svg --enable-id-stripping --shorten-ids

Inline SVG vs External <img>

Inline <svg> <img src="icon.svg"> CSS background-image
CSS/JS access ✅ Full DOM access ❌ None ❌ None
Animation ✅ CSS + JS ✅ SMIL only ✅ CSS only
Caching ❌ Not cached ✅ Cached ✅ Cached
ARIA / accessibility aria-label, <title> alt attribute ❌ Poor
Best for Interactive icons, themed UI Static illustrations Decorative backgrounds

Quick Reference

Task Tool / Method
Draw SVG by hand Any text editor
Design SVG visually Figma, Inkscape, Illustrator
Optimize SVG svgo, scour
Convert SVG → PNG/JPG Toolko Image Converter
Inline SVG in React <svg> tags directly, or import { ReactComponent }
Animate SVG CSS @keyframes on SVG elements, or GSAP
Parse SVG in code xml.etree (Python), encoding/xml (Go), SimpleXML (PHP), DOMParser (JS)

6 Common Mistakes

  1. Missing xmlns on exported SVG. If you generate SVG in code and serve it as a standalone file, include xmlns="http://www.w3.org/2000/svg" on the root element — omitting it breaks rendering in some contexts.

  2. Forgetting viewBox. Without viewBox, the SVG won't scale responsively. Always set viewBox="0 0 W H" where W×H matches your design coordinates.

  3. Using SVG for photographs. SVG traces of photos produce huge files and poor quality. Use JPG, WebP, or AVIF instead.

  4. Unoptimized exports from design tools. Figma exports typically add 2–5× unnecessary data. Always run SVGO before shipping to production.

  5. Injecting untrusted SVG content. SVG supports <script> tags and event handlers (onclick, onload). Never render user-uploaded SVG directly in the page without sanitizing it — this is an XSS vector.

  6. Hardcoding width/height when you want responsive scaling. Remove width and height from the root <svg> and let CSS control the size. Keep viewBox so the proportions are preserved.


Frequently Asked Questions

Can I open an SVG in Photoshop or GIMP?
Yes, but both apps rasterize the SVG to pixels at import. You lose the vector properties. Use Inkscape (free) or Illustrator to edit SVG as vectors.

Why is my SVG blurry when I export it to PNG?
You're likely exporting at 1× screen resolution. Set the export DPI to 144 (2×) or 216 (3×) to get a sharp PNG for high-DPI screens.

Is SVG supported in all browsers?
Yes — all modern browsers (Chrome, Firefox, Safari, Edge) support SVG fully. IE 11 supports SVG but lacks some CSS features. IE 9/10 support basic SVG.

Can I use SVG in an <img> tag?
Yes. <img src="icon.svg" alt="..."> works in all modern browsers. Scripts and external stylesheets inside the SVG are blocked for security.

How do I make an SVG icon change colour on hover?
Inline the SVG in HTML and use CSS: svg:hover path { fill: red; }. This requires the icon to use fill="currentColor" or no fill attribute (so CSS can override it).

What is the difference between SVG and Canvas?
SVG is a retained-mode, DOM-based API — each shape is an element you can inspect and animate with CSS. Canvas is immediate-mode — you paint pixels and the DOM knows nothing about them. SVG is better for interactive diagrams and UI icons; Canvas is better for games, real-time visualizations, and pixel manipulation.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools