What is SVG?
SVG, which stands for Scalable Vector Graphics, is an XML-based markup language for describing two-dimensional vector graphics. Unlike raster image formats like JPEG, PNG, or GIF (which are made up of a fixed grid of pixels), SVG images are composed of mathematical descriptions of shapes, paths, text, and gradients. This fundamental difference brings powerful capabilities to web developers and designers alike.
When you include an SVG in your HTML document, you are not embedding a static picture. You are embedding a living, XML-based description that the browser renders dynamically. Every circle, every curve, every text element is a DOM node that can be styled with CSS, animated with JavaScript, or manipulated just like any other HTML element.
Here is the simplest possible SVG β a red circle β embedded directly in HTML:
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" fill="crimson" />
</svg>
The xmlns attribute is required when using inline SVG in HTML5 documents (though modern browsers may be forgiving if you omit it, it is best practice to always include it). The coordinate system starts from the top-left corner, and elements are drawn in the order they appear β later elements appear on top of earlier ones, much like the z-index in CSS.
Why SVG Matters
π Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →SVG solves several critical problems that raster images simply cannot address, making it an essential tool in modern web development:
- Resolution Independence: SVG graphics look crisp on any screen, from a 300px-wide mobile viewport to a 4K desktop monitor or a high-DPI printed page. Because they are vectors, they scale without losing quality.
- Small File Size (for certain types of graphics): Icons, logos, charts, and diagrams are often much smaller as SVG code than their raster equivalents, especially when optimized. A complex photograph is better suited for JPEG, but a geometric logo shines as SVG.
- Full DOM Access: Every element inside an inline SVG becomes part of the document object model. You can attach event listeners, change attributes dynamically, or animate properties with CSS or the Web Animations API.
- CSS Styling: You can style SVG elements using standard CSS properties β fills, strokes, opacity, transforms, and even complex filters β often with greater control than CSS on HTML elements.
- Animation Capabilities: SVG supports declarative animation via the
<animate>element, as well as powerful JavaScript-driven animations for interactive data visualizations, games, and UI effects. - Accessibility: SVG allows you to embed semantic metadata, titles, and descriptions that screen readers can consume, making vector graphics more accessible than
<img>with alt text alone.
Getting Started with SVG in HTML
There are several ways to include SVG in an HTML document. Each method has different implications for styling, scripting, and caching.
Method 1: Inline SVG (Recommended for Interactivity)
Inline SVG places the entire SVG markup directly inside your HTML. This gives you the most control: you can style it with your page's CSS, manipulate it with JavaScript, and it incurs no extra HTTP request.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Inline SVG Example</title>
<style>
.hover-circle:hover {
fill: gold;
cursor: pointer;
transition: fill 0.3s;
}
</style>
</head>
<body>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="60" fill="steelblue" class="hover-circle" />
<text x="100" y="105" text-anchor="middle" fill="white" font-size="18">SVG</text>
</svg>
</body>
</html>
Notice how the CSS class .hover-circle targets the SVG <circle> element directly. The browser treats it as a first-class citizen in the DOM. The fill property is an SVG presentation attribute that maps to a CSS property, so CSS transitions work beautifully.
Method 2: SVG via <img> Tag
Use the <img> element when your SVG is a static asset that doesn't need dynamic manipulation β like a logo or illustration. This method is simple and benefits from browser caching.
<img src="logo.svg" alt="Company logo" width="150" height="50">
Important limitation: SVGs loaded via <img> or as a CSS background-image cannot be manipulated by JavaScript and cannot inherit styles from the parent page's CSS. The SVG must contain all its styling internally.
Method 3: SVG via <object> or <iframe>
The <object> element provides a middle ground: the SVG remains an external file (cacheable), yet you can access its internal DOM from JavaScript (subject to same-origin restrictions).
<object data="interactive-map.svg" type="image/svg+xml" width="800" height="600">
Your browser does not support SVGs.
</object>
The fallback content inside the <object> tag displays if the browser cannot render the SVG. This pattern is useful for progressive enhancement.
Common SVG Shapes
SVG provides a set of basic shape elements that cover most needs. Here is a comprehensive example demonstrating all fundamental shapes:
<svg width="500" height="300" xmlns="http://www.w3.org/2000/svg">
<!-- Rectangle -->
<rect x="10" y="10" width="100" height="60" fill="tomato" rx="8" />
<!-- Circle -->
<circle cx="160" cy="40" r="30" fill="seagreen" />
<!-- Ellipse -->
<ellipse cx="250" cy="40" rx="40" ry="20" fill="goldenrod" />
<!-- Line -->
<line x1="320" y1="20" x2="400" y2="60" stroke="navy" stroke-width="3" />
<!-- Polygon (triangle) -->
<polygon points="430,10 470,60 390,60" fill="orchid" />
<!-- Polyline (open shape) -->
<polyline points="10,100 50,130 90,100 130,140" fill="none" stroke="coral" stroke-width="3" />
<!-- Path (curved shape) -->
<path d="M 200 100 Q 250 60 300 100 T 400 100" fill="none" stroke="teal" stroke-width="4" />
<!-- Text -->
<text x="250" y="180" text-anchor="middle" font-family="Arial" font-size="24" fill="darkslateblue">
SVG Shapes Demo
</text>
</svg>
Each shape has its own set of specific attributes. The <path> element is the most powerful β its d attribute uses a compact command language to describe complex curves, arcs, and combined shapes. Mastering path commands (M, L, C, Q, A, Z) unlocks virtually any vector illustration.
The <path> Element in Detail
Paths are the backbone of SVG. Let's break down a more sophisticated path example:
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<path
d="M 30 100
C 30 30, 170 30, 170 100
S 30 170, 30 100
Z"
fill="mediumvioletred"
stroke="darkred"
stroke-width="4"
/>
</svg>
Breaking down the d attribute:
M 30 100β Move to absolute coordinates (30, 100) without drawing.C 30 30, 170 30, 170 100β Cubic BΓ©zier curve. The first pair (30, 30) is the first control point, the second pair (170, 30) is the second control point, and (170, 100) is the end point.S 30 170, 170 100β Smooth BΓ©zier curve. It mirrors the previous control point automatically, requiring only one explicit control point (30, 170) and an end point (170, 100).Zβ Close the path by drawing a straight line back to the starting point.
Gradients and Patterns
SVG supports linear and radial gradients defined in a <defs> section. These gradients can be referenced by ID, promoting reusability.
<svg width="400" height="200" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="fadeGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="royalblue" stop-opacity="1" />
<stop offset="50%" stop-color="violet" stop-opacity="0.7" />
<stop offset="100%" stop-color="crimson" stop-opacity="1" />
</linearGradient>
<radialGradient id="sunGradient" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="gold" />
<stop offset="100%" stop-color="orangered" />
</radialGradient>
</defs>
<rect x="10" y="10" width="180" height="180" fill="url(#fadeGradient)" rx="10" />
<circle cx="290" cy="100" r="80" fill="url(#sunGradient)" />
</svg>
The <defs> element stores definitions without rendering them. Anything inside <defs> must be explicitly referenced (via url(#id), <use>, or other means) to appear on screen. This pattern is essential for keeping your SVG code DRY.
Strokes, Dashes, and Advanced Styling
Beyond simple fill and stroke, SVG offers fine-grained control over how outlines are drawn:
<svg width="400" height="150" xmlns="http://www.w3.org/2000/svg">
<line
x1="30" y1="30" x2="370" y2="30"
stroke="darkgreen"
stroke-width="8"
stroke-linecap="round"
stroke-dasharray="20, 10, 5, 10"
/>
<circle
cx="200" cy="90" r="40"
fill="none"
stroke="darkorange"
stroke-width="6"
stroke-dasharray="8, 4"
stroke-linecap="butt"
/>
</svg>
The stroke-dasharray attribute defines a pattern of dash lengths and gap lengths. The values 20, 10, 5, 10 mean: draw a dash of length 20, a gap of 10, a dash of 5, a gap of 10, then repeat. stroke-linecap controls the shape at the ends of strokes: round, butt, or square.
Responsive SVG
Making SVG scale properly requires understanding the viewBox attribute and the interplay with width and height. The viewBox defines the internal coordinate system, while width and height define the element's size in the page layout.
<svg viewBox="0 0 200 100" width="100%" height="auto" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="180" height="80" fill="teal" rx="10" />
<text x="100" y="55" text-anchor="middle" fill="white" font-size="16">
Responsive SVG
</text>
</svg>
By setting width="100%" and omitting a fixed height (or using height="auto"), the SVG will scale to fill its container while maintaining the aspect ratio defined by the viewBox. The viewBox values are min-x min-y width height β here, the internal coordinate space runs from (0, 0) to (200, 100).
For truly responsive icons, a common pattern is:
<svg viewBox="0 0 24 24" width="1em" height="1em" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 22h20L12 2z" fill="currentColor" />
</svg>
Using width="1em" height="1em" makes the icon scale proportionally to the surrounding text size. The fill="currentColor" magic word inherits the current CSS text color, so the icon automatically matches the surrounding typography.
SVG Sprites and the <use> Element
SVG sprites allow you to define symbols once and reuse them multiple times β similar to how CSS sprites worked, but far more elegant:
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<defs>
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24">
<path d="M15.5 14h-.79l-.28-.27A6.47 6.47 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.59 19l-5.09-5zm-6 0A4.5 4.5 0 1 1 14 9.5 4.5 4.5 0 0 1 9.5 14z" />
</symbol>
</defs>
</svg>
<!-- Usage elsewhere in the HTML -->
<svg width="48" height="48">
<use href="#icon-home" fill="darkblue" />
</svg>
<svg width="48" height="48">
<use href="#icon-search" fill="darkblue" />
</svg>
Key points about sprites:
- The sprite sheet SVG is hidden with
display: none;β it will not take up space or render visibly. - Each
<symbol>has its ownviewBox, making it self-contained. - The
<use>element references symbols by ID withhref="#id"(modern syntax; older code may usexlink:href). - You can override
filland other presentation attributes on the<use>element, provided the symbol's internal elements do not have those attributes hardcoded.
Clipping and Masking
SVG allows you to define clipping paths and masks to control which parts of elements are visible:
<svg width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="circleClip">
<circle cx="150" cy="100" r="60" />
</clipPath>
</defs>
<rect x="80" y="40" width="140" height="120" fill="mediumslateblue" />
<image
href="https://placekitten.com/200/200"
x="80" y="40" width="140" height="120"
clip-path="url(#circleClip)"
/>
</svg>
A <clipPath> restricts rendering to the area defined by its contents β anything outside the clipping region is completely hidden. Masks, by contrast, use luminance or alpha values to control opacity per-pixel, enabling soft-edged reveals.
SVG Filters
SVG filters provide powerful graphical effects like blur, shadow, and color manipulation, all declaratively:
<svg width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="4" dy="6" stdDeviation="3" flood-color="rgba(0,0,0,0.4)" />
</filter>
<filter id="blurEffect">
<feGaussianBlur stdDeviation="5" />
</filter>
</defs>
<rect x="30" y="30" width="100" height="80" fill="lightseagreen" filter="url(#dropShadow)" />
<circle cx="210" cy="70" r="40" fill="hotpink" filter="url(#blurEffect)" opacity="0.7" />
</svg>
Filter effects like <feDropShadow>, <feGaussianBlur>, <feColorMatrix>, and <feMerge> can be combined in chains to create sophisticated visual results β all rendered natively by the browser without any external image processing.
SVG Animation with <animate>
SVG includes a declarative animation engine that works without any JavaScript. While CSS animations are now more common, native SVG animations remain useful for certain scenarios:
<svg width="300" height="100" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="40" height="40" fill="coral">
<animate
attributeName="x"
values="10; 250; 10"
dur="3s"
repeatCount="indefinite"
/>
<animate
attributeName="fill"
values="coral; seagreen; coral"
dur="3s"
repeatCount="indefinite"
/>
</rect>
<circle cx="150" cy="50" r="20" fill="royalblue">
<animate
attributeName="r"
values="20; 35; 20"
dur="2s"
repeatCount="indefinite"
/>
<animate
attributeName="opacity"
values="1; 0.4; 1"
dur="2s"
repeatCount="indefinite"
/>
</circle>
</svg>
The <animate> element changes an attribute of its parent element over time. The values attribute defines keyframes (semicolon-separated), dur sets the duration, and repeatCount="indefinite" loops the animation forever. Multiple <animate> elements can animate different properties simultaneously.
Interacting with SVG via JavaScript
Because inline SVG becomes part of the DOM, you can attach event handlers, query elements, and dynamically modify attributes just like any HTML element:
<svg id="interactive-svg" width="400" height="300" xmlns="http://www.w3.org/2000/svg">
<rect id="click-rect" x="100" y="100" width="200" height="100" fill="indigo" rx="10" />
<text id="click-counter" x="200" y="155" text-anchor="middle" fill="white" font-size="20">
Clicks: 0
</text>
</svg>
<script>
(() => {
const rect = document.getElementById('click-rect');
const counter = document.getElementById('click-counter');
let clicks = 0;
rect.addEventListener('click', () => {
clicks += 1;
counter.textContent = `Clicks: ${clicks}`;
rect.setAttribute('fill', clicks % 2 === 0 ? 'indigo' : 'darkorange');
});
rect.addEventListener('mouseenter', () => {
rect.style.cursor = 'pointer';
rect.style.opacity = '0.8';
});
rect.addEventListener('mouseleave', () => {
rect.style.opacity = '1';
});
})();
</script>
This example demonstrates DOM queries (getElementById), event listeners (click, mouseenter, mouseleave), text content manipulation, attribute changes, and inline style modifications β all targeting SVG nodes directly. The integration between SVG and the HTML DOM is seamless.
Creating SVG Charts and Data Visualizations
SVG excels at data visualization. Here is a simple bar chart generated programmatically:
<svg id="chart" width="400" height="250" xmlns="http://www.w3.org/2000/svg">
<!-- Axes rendered statically -->
<line x1="40" y1="20" x2="40" y2="220" stroke="black" stroke-width="2" />
<line x1="40" y1="220" x2="380" y2="220" stroke="black" stroke-width="2" />
</svg>
<script>
(() => {
const data = [
{ label: 'Jan', value: 45 },
{ label: 'Feb', value: 72 },
{ label: 'Mar', value: 38 },
{ label: 'Apr', value: 91 },
{ label: 'May', value: 64 },
{ label: 'Jun', value: 53 },
];
const chart = document.getElementById('chart');
const chartHeight = 200; // from y=20 to y=220
const maxValue = Math.max(...data.map(d => d.value));
const barWidth = 40;
const gap = 15;
const startX = 60;
data.forEach((item, i) => {
const barHeight = (item.value / maxValue) * chartHeight;
const x = startX + i * (barWidth + gap);
const y = 220 - barHeight;
// Create bar
const bar = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
bar.setAttribute('x', x);
bar.setAttribute('y', y);
bar.setAttribute('width', barWidth);
bar.setAttribute('height', barHeight);
bar.setAttribute('fill', `hsl(${i * 40}, 70%, 55%)`);
bar.setAttribute('rx', '4');
chart.appendChild(bar);
// Create label
const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
label.setAttribute('x', x + barWidth / 2);
label.setAttribute('y', 240);
label.setAttribute('text-anchor', 'middle');
label.setAttribute('fill', 'black');
label.setAttribute('font-size', '12');
label.textContent = item.label;
chart.appendChild(label);
// Create value text atop bar
const valueText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
valueText.setAttribute('x', x + barWidth / 2);
valueText.setAttribute('y', y - 8);
valueText.setAttribute('text-anchor', 'middle');
valueText.setAttribute('fill', 'darkslategray');
valueText.setAttribute('font-size', '11');
valueText.textContent = item.value;
chart.appendChild(valueText);
});
})();
</script>
Note the use of document.createElementNS('http://www.w3.org/2000/svg', ...) β when creating SVG elements via JavaScript, you must use the namespace-aware method, because SVG elements belong to a different XML namespace than HTML elements.
Accessibility in SVG
Making SVG accessible involves providing semantic metadata and ensuring screen readers can convey the content meaningfully:
<svg viewBox="0 0 200 100" width="400" height="200" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="title desc">
<title id="title">Quarterly Revenue Growth</title>
<desc id="desc">A bar chart showing revenue increasing from 50K in Q1 to 95K in Q4</desc>
<rect x="20" y="80" width="30" height="20" fill="steelblue">
<title>Q1: 50,000</title>
</rect>
<rect x="60" y="60" width="30" height="40" fill="steelblue">
<title>Q2: 65,000</title>
</rect>
<rect x="100" y="40" width="30" height="60" fill="steelblue">
<title>Q3: 80,000</title>
</rect>
<rect x="140" y="20" width="30" height="80" fill="steelblue">
<title>Q4: 95,000</title>
</rect>
</svg>
Best practices for accessible SVG:
- Use
role="img"to indicate the SVG is a graphic (unless it contains interactive controls). - Provide a
<title>and<desc>linked viaaria-labelledbyandaria-describedby. - For data visualizations, include individual
<title>elements on key parts so screen readers can navigate data points. - If the SVG is purely decorative (like a background pattern), use
aria-hidden="true". - For interactive SVG widgets, use proper ARIA roles (
role="button",role="slider", etc.) and ensure keyboard operability.
Best Practices
- Always include the
xmlnsattribute on inline SVGs. While browsers may render without it in HTML5, omitting it can cause issues when the markup is copied to other contexts or when using certain SVG features. - Use
viewBoxfor scalability. Define a coordinate system independent of the rendered size. This decouples your internal geometry from layout dimensions and makes responsive design straightforward. - Minimize path complexity. Remove unnecessary decimal places, collapse repeated commands, and use relative commands (
m,c,linstead ofM,C,L) where appropriate to reduce file size. - Keep
<defs>organized. Group gradients, filters, symbols, and clip paths inside<defs>at the top of your SVG. This improves readability and maintainability. - Prefer inline SVG for interactive elements. Use
<img>for static assets, but switch to inline SVG whenever you need CSS styling, JavaScript interaction, or animation. - Use
currentColorfor icon fills. This allows a single SVG icon to adapt to surrounding text color, making them truly reusable across different contexts. - Optimize SVGs before deployment. Tools like SVGO (SVG Optimizer) can strip unnecessary metadata, comments, and hidden elements, often reducing file size by 30β50% without visual change.
- Test across browsers. While SVG support is excellent in modern browsers, filter effects, advanced animations, and certain CSS-on-SVG combinations can behave differently. Always test on your target platforms.
- Provide fallback content. When using
<object>or<iframe>, include text or an<img>fallback for very old or constrained environments. - Don't forget accessibility. A few extra attributes β
role,aria-labelledby,<title>,<desc>β transform an opaque graphic into a navigable, understandable element for assistive technologies. - Avoid excessive DOM nodes. For very complex illustrations with thousands of elements, consider rendering to a
<canvas>instead, as SVG DOM overhead can impact performance. SVG shines for illustrations up to moderate complexity, UI icons, and data visualizations with hundreds (not tens of thousands) of elements. - Use CSS for styling, not presentation attributes, when theming matters. Presentation attributes like
fill="red"have high specificity and cannot be overridden by regular CSS rules. For themable components, rely on CSS classes orcurrentColor.
Conclusion
SVG is far