SVG Basics
SVG (Scalable Vector Graphics) is an XML-based image format that describes graphics using mathematical shapes rather than pixels. SVG images are resolution-independent — they look perfectly sharp at any size, from a tiny favicon to a massive billboard screen.
SVG is natively supported in all modern browsers and can be placed inside HTML in multiple ways: as an <img> tag, as a CSS background, or inline directly in the HTML document.
1. Why SVG?
![]()
Source: Wikimedia Commons – Bitmap VS SVG.svg · CC BY-SA 2.5
Text description: The left side shows a pixelated, blocky star icon when zoomed in (a raster/bitmap image). The right side shows the same star zoomed in, still perfectly sharp and smooth (an SVG vector image). This demonstrates that SVG maintains quality at any resolution.
| Feature | Raster (PNG/JPEG) | SVG |
|---|---|---|
| Quality at any size | Degrades (pixelates) | Always sharp |
| File size for icons | Can be large | Usually tiny |
| Editable with CSS | No | Yes |
| Animatable | No (without JS) | Yes (CSS or JS) |
| Accessibility | Via alt only | Built-in text & ARIA |
| Search engine readable | No | Yes (it's XML text) |
| Best for | Photos | Icons, logos, charts, illustrations |
2. Adding SVG to HTML
Method 1 — As an <img> Tag
<img src="logo.svg" alt="Nandhoo logo" width="200" height="60">
- Simple, cacheable, consistent with other images
- Cannot be styled or animated with CSS
- Cannot be manipulated with JavaScript
Method 2 — As a CSS Background
.hero {
background-image: url('pattern.svg');
background-size: cover;
}
- Good for decorative patterns and textures
- No accessibility — cannot have
alttext
Method 3 — Inline SVG in HTML
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
width="100"
height="100"
role="img"
aria-label="Blue circle icon"
>
<circle cx="50" cy="50" r="45" fill="#3b82f6" />
</svg>
- Can be styled with CSS (fill, stroke, transitions)
- Can be animated with CSS or manipulated with JavaScript
- Extra markup in your HTML source
Which to Use?
Icon that needs hover colour change or animation? → Inline SVG
Logo that just needs to display? → <img src="logo.svg">
Decorative background pattern? → CSS background-image
3. SVG Coordinate System and viewBox
SVG has its own internal coordinate system defined by viewBox.
<svg viewBox="0 0 200 100" width="400" height="200">
<!--
viewBox="0 0 200 100"
↑ ↑ ↑ ↑ ↑
│ │ │ │ └── internal height of canvas
│ │ │ └────── internal width of canvas
│ │ └────────── starting y coordinate
│ └──────────── starting x coordinate
└──────────────── attribute name
-->
</svg>
The viewBox coordinates are internal units. The width and height attributes control the actual display size in the browser. This is what makes SVG scale perfectly:
<!-- Both of these display the same drawing — just at different sizes -->
<svg viewBox="0 0 100 100" width="50" height="50"> <!-- small -->
<svg viewBox="0 0 100 100" width="500" height="500"> <!-- large -->
SVG's coordinate origin (0,0) is the top-left corner. x increases rightward, y increases downward.
4. Basic SVG Shapes
Rectangle — <rect>
<svg viewBox="0 0 200 100" width="400" height="200">
<!-- Basic rectangle -->
<rect x="10" y="10" width="80" height="50" fill="#3b82f6" />
<!-- Rectangle with rounded corners -->
<rect x="110" y="10" width="80" height="50" rx="12" ry="12" fill="#10b981" />
<!-- Rectangle with stroke (border) and no fill -->
<rect x="10" y="70" width="80" height="20"
fill="none" stroke="#ef4444" stroke-width="2" />
</svg>
| Attribute | Meaning |
|---|---|
x, y | Top-left position |
width, height | Size |
rx, ry | Corner radius |
fill | Background colour (or none) |
stroke | Border colour |
stroke-width | Border thickness |
Circle — <circle>
<svg viewBox="0 0 200 100" width="400" height="200">
<circle cx="50" cy="50" r="40" fill="#f59e0b" />
<circle cx="150" cy="50" r="40" fill="none" stroke="#8b5cf6" stroke-width="3" />
</svg>
| Attribute | Meaning |
|---|---|
cx, cy | Centre x and y |
r | Radius |
Ellipse — <ellipse>
<svg viewBox="0 0 200 100" width="400" height="200">
<ellipse cx="100" cy="50" rx="80" ry="40" fill="#ec4899" />
</svg>
| Attribute | Meaning |
|---|---|
rx | Horizontal radius |
ry | Vertical radius |
Line — <line>
<svg viewBox="0 0 200 100" width="400" height="200">
<line x1="10" y1="10" x2="190" y2="90"
stroke="#374151" stroke-width="2" stroke-linecap="round" />
</svg>
Polyline — <polyline>
A series of connected line segments (not closed).
<svg viewBox="0 0 200 100" width="400" height="200">
<!-- A simple zigzag line chart -->
<polyline
points="0,80 40,30 80,60 120,20 160,50 200,10"
fill="none"
stroke="#3b82f6"
stroke-width="2"
/>
</svg>
Polygon — <polygon>
A closed shape defined by a series of connected points.
<svg viewBox="0 0 200 200" width="200" height="200">
<!-- Triangle -->
<polygon points="100,10 190,190 10,190" fill="#f59e0b" />
<!-- Six-pointed star -->
<polygon
points="100,10 120,80 190,80 135,125 155,195 100,150 45,195 65,125 10,80 80,80"
fill="#ef4444"
/>
</svg>
5. The <path> Element
<path> is the most powerful SVG element. It can draw any shape using a series of commands in the d attribute.
<svg viewBox="0 0 200 200" width="200" height="200">
<!-- A simple curved shape -->
<path
d="M 20 80 C 20 20, 180 20, 180 80 S 180 160, 100 160 S 20 160, 20 80"
fill="#6366f1"
/>
</svg>
Path Commands
| Command | Absolute | Relative | Meaning |
|---|---|---|---|
M / m | M x y | m dx dy | Move to (no drawing) |
L / l | L x y | l dx dy | Line to |
H / h | H x | h dx | Horizontal line |
V / v | V y | v dy | Vertical line |
C / c | C x1 y1, x2 y2, x y | relative | Cubic Bézier curve |
Q / q | Q x1 y1, x y | relative | Quadratic Bézier |
A / a | A rx ry rotation large-arc sweep x y | relative | Arc |
Z / z | Z | Close path (line back to start) |
Uppercase = absolute coordinates (relative to SVG origin). Lowercase = relative to current position.
Example — A Heart Shape
<svg viewBox="0 0 100 90" width="200" height="180">
<path
d="M 50 85 C 25 70, 0 50, 0 30 C 0 10, 15 0, 30 0 C 40 0, 48 5, 50 12 C 52 5, 60 0, 70 0 C 85 0, 100 10, 100 30 C 100 50, 75 70, 50 85 Z"
fill="#ef4444"
/>
</svg>
6. Text in SVG
SVG includes native text rendering. Text in SVG is real, selectable, and accessible.
<svg viewBox="0 0 300 80" width="300" height="80">
<!-- Basic text -->
<text x="10" y="30" font-size="20" fill="#1e293b" font-family="system-ui, sans-serif">
Hello, Nandhoo!
</text>
<!-- Centred text -->
<text x="150" y="70" text-anchor="middle" font-size="16" fill="#64748b">
Scalable Vector Graphics
</text>
</svg>
Text Attributes
| Attribute | Values | Meaning |
|---|---|---|
x, y | numbers | Position of baseline start |
text-anchor | start middle end | Horizontal alignment relative to x |
dominant-baseline | auto middle hanging | Vertical alignment |
font-size | number | Size in SVG units |
font-family | font names | Font |
fill | colour | Text colour |
font-weight | normal bold | Weight |
Text Along a Path
<svg viewBox="0 0 300 100" width="300" height="100">
<defs>
<path id="curve" d="M 20 80 Q 150 10 280 80" />
</defs>
<text font-size="16" fill="#6366f1">
<textPath href="#curve">Text flowing along a curved path!</textPath>
</text>
</svg>
7. Grouping with <g>
<g> (group) wraps multiple elements so you can transform, style, or manipulate them together.
<svg viewBox="0 0 200 200" width="200" height="200">
<!-- House icon made from grouped shapes -->
<g id="house" stroke="#1e293b" stroke-width="2">
<!-- Roof -->
<polygon points="100,20 180,90 20,90" fill="#f59e0b" />
<!-- Walls -->
<rect x="40" y="90" width="120" height="90" fill="#e2e8f0" />
<!-- Door -->
<rect x="80" y="130" width="40" height="50" fill="#a78bfa" />
<!-- Window -->
<rect x="50" y="105" width="30" height="25" fill="#93c5fd" />
<rect x="120" y="105" width="30" height="25" fill="#93c5fd" />
</g>
</svg>
8. Transforms
SVG elements support transforms: translate, rotate, scale, and skew.
<svg viewBox="0 0 300 200" width="300" height="200">
<!-- Original square -->
<rect x="10" y="75" width="50" height="50" fill="#3b82f6" />
<!-- Translated (moved) -->
<rect x="10" y="75" width="50" height="50" fill="#10b981"
transform="translate(80, 0)" />
<!-- Rotated 45° around its centre -->
<rect x="10" y="75" width="50" height="50" fill="#f59e0b"
transform="translate(190, 100) rotate(45) translate(-25, -25)" />
<!-- Scaled to 1.5× -->
<rect x="10" y="75" width="50" height="50" fill="#ef4444"
transform="translate(240, 50) scale(1.5)" />
</svg>
Transform Functions
| Function | Example | Effect |
|---|---|---|
translate(x, y) | translate(50, 20) | Move right 50, down 20 |
rotate(deg) | rotate(45) | Rotate 45° around origin |
rotate(deg, cx, cy) | rotate(45, 50, 50) | Rotate around point (50,50) |
scale(factor) | scale(2) | Double size |
scale(x, y) | scale(2, 0.5) | Scale x and y independently |
skewX(deg) | skewX(20) | Skew along x axis |
9. <defs> — Reusable Definitions
<defs> stores shapes that can be reused multiple times without re-drawing them.
Reusing Shapes with <use>
<svg viewBox="0 0 300 100" width="300" height="100">
<defs>
<circle id="dot" r="12" fill="#3b82f6" />
</defs>
<!-- Reuse the same circle in three positions -->
<use href="#dot" x="30" y="50" />
<use href="#dot" x="80" y="50" fill="#ef4444" /> <!-- override fill -->
<use href="#dot" x="130" y="50" fill="#10b981" />
</svg>
Gradients
<svg viewBox="0 0 200 100" width="400" height="200">
<defs>
<!-- Linear gradient from blue to purple -->
<linearGradient id="gradient-bp" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#3b82f6" />
<stop offset="100%" stop-color="#8b5cf6" />
</linearGradient>
<!-- Radial gradient golden glow -->
<radialGradient id="gradient-gold" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#fbbf24" />
<stop offset="100%" stop-color="#92400e" />
</radialGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#gradient-bp)" />
<circle cx="155" cy="50" r="40" fill="url(#gradient-gold)" />
</svg>
Clipping Paths
<svg viewBox="0 0 200 200" width="200" height="200">
<defs>
<!-- Circle clip mask -->
<clipPath id="circle-clip">
<circle cx="100" cy="100" r="90" />
</clipPath>
</defs>
<!-- Image clipped to a circle -->
<image
href="landscape.jpg"
x="0" y="0" width="200" height="200"
clip-path="url(#circle-clip)"
/>
</svg>
Patterns
<svg viewBox="0 0 200 200" width="200" height="200">
<defs>
<pattern id="dots" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="5" cy="5" r="3" fill="#6366f1" />
</pattern>
</defs>
<rect x="0" y="0" width="200" height="200" fill="url(#dots)" />
</svg>
10. Filters and Effects
SVG filters apply visual effects like blur, glow, and drop shadows.
<svg viewBox="0 0 200 100" width="400" height="200">
<defs>
<!-- Blur filter -->
<filter id="blur-filter">
<feGaussianBlur stdDeviation="3" />
</filter>
<!-- Drop shadow filter -->
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="4" dy="4" stdDeviation="3" flood-color="#00000033" />
</filter>
</defs>
<circle cx="50" cy="50" r="40" fill="#3b82f6" filter="url(#blur-filter)" />
<circle cx="150" cy="50" r="40" fill="#ef4444" filter="url(#shadow)" />
</svg>
11. CSS Styling of SVG
SVG elements can be styled with CSS using both presentation attributes and class-based rules.
Using CSS Classes
<style>
.icon-primary { fill: #3b82f6; }
.icon-secondary { fill: #10b981; }
.icon-stroke { fill: none; stroke: #1e293b; stroke-width: 2; }
.icon-primary:hover { fill: #1d4ed8; transition: fill 0.2s; }
</style>
<svg viewBox="0 0 100 100" width="100" height="100">
<circle cx="50" cy="50" r="40" class="icon-primary" />
<rect x="30" y="30" width="40" height="40" class="icon-stroke" />
</svg>
CSS Properties That Work on SVG Elements
| CSS property | SVG equivalent attribute | What it styles |
|---|---|---|
fill | fill | Inside colour |
stroke | stroke | Border colour |
stroke-width | stroke-width | Border thickness |
opacity | opacity | Overall transparency |
fill-opacity | fill-opacity | Fill transparency only |
stroke-opacity | stroke-opacity | Stroke transparency only |
stroke-dasharray | stroke-dasharray | Dashed stroke pattern |
stroke-linecap | stroke-linecap | Line end caps (butt/round/square) |
transform | transform | Translate, rotate, scale |
12. Animating SVG with CSS
Rotate an Icon
<style>
.spin { animation: rotate 2s linear infinite; transform-origin: center; }
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>
<svg viewBox="0 0 100 100" width="80" height="80">
<g class="spin">
<circle cx="50" cy="50" r="40" fill="none" stroke="#3b82f6" stroke-width="4" stroke-dasharray="20 10" />
</g>
</svg>
Animated Stroke Drawing Effect
<style>
.draw-path {
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation: draw 2s ease forwards;
}
@keyframes draw {
to { stroke-dashoffset: 0; }
}
</style>
<svg viewBox="0 0 200 100" width="400" height="200">
<path
class="draw-path"
d="M 10 50 Q 100 10 190 50"
fill="none"
stroke="#6366f1"
stroke-width="3"
/>
</svg>
Pulse Effect
<style>
.pulse {
animation: pulse 1.5s ease-in-out infinite;
transform-origin: center;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.15); opacity: 0.7; }
}
</style>
<svg viewBox="0 0 100 100" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="#ef4444" class="pulse" />
</svg>
13. JavaScript and SVG Interaction
SVG is part of the DOM and fully accessible from JavaScript.
<svg id="my-svg" viewBox="0 0 200 200" width="200" height="200">
<circle id="target-circle" cx="100" cy="100" r="60" fill="#3b82f6"
style="cursor:pointer" />
<text x="100" y="105" text-anchor="middle" fill="white" font-size="16"
id="count-label" pointer-events="none">Click me!</text>
</svg>
<script>
const circle = document.getElementById('target-circle');
const label = document.getElementById('count-label');
const colours = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'];
let count = 0;
circle.addEventListener('click', () => {
count++;
// Cycle through colours
circle.setAttribute('fill', colours[count % colours.length]);
label.textContent = `Clicked ${count}×`;
});
</script>
Creating SVG Elements Dynamically
// Create a circle and add it to an existing SVG
const svg = document.getElementById('my-svg');
const NS = 'http://www.w3.org/2000/svg'; // SVG namespace
const circle = document.createElementNS(NS, 'circle');
circle.setAttribute('cx', '50');
circle.setAttribute('cy', '50');
circle.setAttribute('r', '30');
circle.setAttribute('fill', '#10b981');
svg.appendChild(circle);
// Animate position with requestAnimationFrame
let frame = 0;
function animate() {
const x = 100 + Math.sin(frame * 0.05) * 60;
const y = 100 + Math.cos(frame * 0.05) * 60;
circle.setAttribute('cx', x.toFixed(1));
circle.setAttribute('cy', y.toFixed(1));
frame++;
requestAnimationFrame(animate);
}
animate();
Important: Always use
createElementNSwith the SVG namespace URI'http://www.w3.org/2000/svg'when creating SVG elements in JavaScript.createElementwon't work correctly.
14. SVG Accessibility
SVGs should be accessible — especially icons and charts.
Decorative SVG — Hide from Screen Readers
<!-- Decorative icon — screen readers will ignore it -->
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24" width="24" height="24">
<path d="M12 2L2 7l10 5 10-5-10-5z" fill="currentColor"/>
</svg>
Meaningful SVG — Describe It
<!-- Standalone meaningful icon — must be labelled -->
<svg role="img" aria-labelledby="star-title star-desc"
viewBox="0 0 100 100" width="100" height="100">
<title id="star-title">Achievement star</title>
<desc id="star-desc">A gold star icon representing a completed achievement or award.</desc>
<polygon points="50,5 61,35 95,35 68,57 79,91 50,70 21,91 32,57 5,35 39,35"
fill="#fbbf24" />
</svg>
SVG Within an <img> Tag
When using <img src="icon.svg">, describe it only in the alt attribute:
<img src="achievement-star.svg" alt="Achievement star — course completed" width="80" height="80">
Accessible SVG Chart
<figure>
<figcaption>Monthly active users — Q1 2025</figcaption>
<svg role="img" aria-label="Bar chart: January 1200, February 1850, March 2400"
viewBox="0 0 320 180" width="320" height="180">
<!-- January -->
<rect x="20" y="80" width="60" height="80" fill="#3b82f6" />
<!-- February -->
<rect x="130" y="20" width="60" height="140" fill="#10b981" />
<!-- March -->
<rect x="240" y="0" width="60" height="160" fill="#6366f1" />
<!-- Labels -->
<text x="50" y="175" text-anchor="middle" font-size="12" fill="#374151">Jan</text>
<text x="160" y="175" text-anchor="middle" font-size="12" fill="#374151">Feb</text>
<text x="270" y="175" text-anchor="middle" font-size="12" fill="#374151">Mar</text>
</svg>
</figure>
15. Building a Reusable SVG Icon System
Instead of repeating SVG markup, define all icons in a hidden <svg> at the top of the page and reference them with <use>.
<!-- Hidden sprite at the top of the page -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
</symbol>
<symbol id="icon-code" viewBox="0 0 24 24">
<path d="M9.4 16.6 4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0 4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/>
</symbol>
<symbol id="icon-star" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
</symbol>
</svg>
<!-- Use icons anywhere with a single line -->
<svg width="24" height="24" aria-hidden="true" focusable="false">
<use href="#icon-home" />
</svg>
<svg width="24" height="24" aria-hidden="true" focusable="false">
<use href="#icon-code" />
</svg>
Style icons with CSS fill: currentColor so they inherit their colour from the parent text:
svg { fill: currentColor; }
.nav-link { color: #3b82f6; }
/* The icon inside .nav-link automatically turns blue */
16. Optimising SVGs
Raw SVG exported from design tools (Figma, Illustrator) often contains unnecessary metadata. Use SVGO to clean it up.
# Install globally
npm install -g svgo
# Optimise a single file
svgo icon.svg -o icon.min.svg
# Optimise a folder
svgo --folder ./icons
Typical savings: 20–70% smaller file size with no visible quality loss.
Manual Optimisation Tips
<!-- ❌ Exported SVG with editor metadata and unnecessary attributes -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 100 100"
style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">.st0{fill:#333333;}</style>
<circle class="st0" cx="50" cy="50" r="40"/>
</svg>
<!-- ✅ Cleaned up version -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#333"/>
</svg>
17. Common Mistakes
| Mistake | What goes wrong | Fix |
|---|---|---|
No viewBox | SVG has fixed size, won't scale | Always set viewBox="minX minY width height" |
Forgetting aria-hidden on decorative SVGs | Screen readers read out <path> data strings | Add aria-hidden="true" and focusable="false" |
No role="img" on meaningful standalone SVG | Assistive tech doesn't announce it as an image | Add role="img" and aria-labelledby |
Using createElement in JS for SVG | Creates wrong element type — not rendered | Use createElementNS(NS, tagName) |
Not using <title> and <desc> | Chart or logo has no description | Add inside the <svg> for meaningful graphics |
Inline CSS transform-origin buggy cross-browser for SVG | Rotation happens around wrong point | Use transform="rotate(45, cx, cy)" in the attribute, or set transform-box: fill-box in CSS |
| Huge unoptimised SVG files from editors | Unnecessary kilobytes of metadata | Run SVGO before deploying |
| Hard-coded fill colours | Icons can't be recoloured with CSS | Use fill="currentColor" |
18. Mini Exercises
- Create an SVG with a coloured circle, a rectangle with rounded corners, and a line between them.
- Draw a simple house shape using
<polygon>for the roof and<rect>for the walls and door. - Define a linear gradient in
<defs>and apply it as thefillof a large rectangle. - Write an SVG
<text>element that centres "Nandhoo" horizontally in a 300-wide SVG. - Use
<clipPath>to clip a large rectangle to a circular shape. - Animate a circle with CSS: make it pulse (scale in and out) over 1.5 seconds.
- Create an SVG icon sprite with two symbols and reference them with
<use>in two different places on the page.
19. Review Questions
- What does SVG stand for and what makes it different from PNG or JPEG?
- What is the
viewBoxattribute and why does it make SVGs resolution-independent? - What is the difference between
<rect>,<circle>,<polygon>, and<path>? - When would you use
<defs>and<use>together? - How do you apply a CSS hover colour change to an inline SVG element?
- What is
fill="currentColor"and when is it useful? - How do you make a decorative SVG icon invisible to screen readers?
- How do you make a meaningful SVG chart accessible?
- Why should you use
createElementNS(notcreateElement) when creating SVG elements with JavaScript? - What tool is used to optimise SVG file sizes for production?