Scalable Vector Graphics (SVG)
SVG (Scalable Vector Graphics) is an XML-based vector image format for two-dimensional graphics. Unlike raster formats (PNG, JPEG) or the HTML Canvas API, SVG maintains a DOM of all elements, making them scriptable, styleable with CSS, and resolution-independent.
SVG can be used three ways: inline in HTML (inlined SVG), as an external image via <img>, or embedded via <object>. Inline SVG is the most powerful as it allows CSS styling and JavaScript interaction.
SVG provides a set of basic shape elements. Each has attributes for position, size, and geometry.
| Element | Attributes | Description |
|---|---|---|
| <rect> | x, y, width, height, rx, ry | Rectangle with optional rounded corners |
| <circle> | cx, cy, r | Circle centered at (cx, cy) |
| <ellipse> | cx, cy, rx, ry | Ellipse with separate x/y radii |
| <line> | x1, y1, x2, y2 | Straight line between two points |
| <polyline> | points | Connected line segments (open) |
| <polygon> | points | Closed shape (last point connects to first) |
| 1 | <svg viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <!-- Rectangle --> |
| 3 | <rect x="20" y="20" width="80" height="60" rx="8" fill="#00FF41" /> |
| 4 | |
| 5 | <!-- Circle --> |
| 6 | <circle cx="180" cy="50" r="40" fill="#4FC3F7" /> |
| 7 | |
| 8 | <!-- Ellipse --> |
| 9 | <ellipse cx="300" cy="50" rx="50" ry="30" fill="#C084FC" /> |
| 10 | |
| 11 | <!-- Line --> |
| 12 | <line x1="400" y1="20" x2="480" y2="80" stroke="#FF6B6B" stroke-width="3" /> |
| 13 | |
| 14 | <!-- Polyline --> |
| 15 | <polyline points="20,130 60,100 100,130 140,100 180,130" |
| 16 | fill="none" stroke="#FFD93D" stroke-width="3" /> |
| 17 | |
| 18 | <!-- Polygon --> |
| 19 | <polygon points="240,130 280,90 320,130 280,170" |
| 20 | fill="#FB923C" stroke="#FFFFFF" stroke-width="2" /> |
| 21 | </svg> |
The <path> element is the most powerful SVG shape. Its d attribute contains a series of commands that define the geometry. Each command is a single letter followed by coordinates.
| Command | Name | Parameters |
|---|---|---|
| M | Move To | x y |
| L | Line To | x y |
| H | Horizontal Line | x |
| V | Vertical Line | y |
| C | Cubic Bezier | x1 y1 x2 y2 x y |
| Q | Quadratic Bezier | x1 y1 x y |
| A | Arc | rx ry x-rot large-arc sweep x y |
| Z | Close Path | — |
Uppercase commands use absolute coordinates, lowercase use relative coordinates from the current point.
| 1 | <!-- Heart shape using cubic beziers --> |
| 2 | <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> |
| 3 | <path d="M50,85 |
| 4 | C15,55 0,40 15,25 |
| 5 | S35,5 50,25 |
| 6 | C65,5 85,10 85,25 |
| 7 | S85,55 50,85Z" |
| 8 | fill="#FF6B6B" /> |
| 9 | </svg> |
| 10 | |
| 11 | <!-- Arc example --> |
| 12 | <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"> |
| 13 | <path d="M20,20 A80,80 0 0,1 180,20" |
| 14 | fill="none" stroke="#00FF41" stroke-width="4" /> |
| 15 | <path d="M20,180 A80,80 0 0,0 180,180" |
| 16 | fill="none" stroke="#4FC3F7" stroke-width="4" /> |
| 17 | </svg> |
SVG elements can be styled with presentation attributes (inline), CSS properties, or stylesheets. The styling model is similar to HTML with cascading and inheritance.
| Property | Values | Description |
|---|---|---|
| fill | color | none | currentColor | Interior color of shape |
| stroke | color | none | currentColor | Outline color |
| stroke-width | number | Thickness of the outline |
| stroke-linecap | butt | round | square | Shape of line ends |
| stroke-linejoin | miter | round | bevel | Shape of line corners |
| opacity | 0–1 | Overall transparency |
| fill-opacity | 0–1 | Fill transparency only |
| stroke-opacity | 0–1 | Stroke transparency only |
| fill-rule | nonzero | evenodd | Determines inside vs outside for complex paths |
| stroke-dasharray | numbers | Dash pattern (e.g. "5,3") |
| 1 | <svg viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <!-- CSS classes for styling --> |
| 3 | <style> |
| 4 | .dashed { stroke-dasharray: 8, 4; } |
| 5 | .glow { filter: drop-shadow(0 0 6px #00FF41); } |
| 6 | </style> |
| 7 | |
| 8 | <!-- Inline styling --> |
| 9 | <circle cx="60" cy="60" r="40" |
| 10 | fill="none" stroke="#00FF41" stroke-width="4" /> |
| 11 | |
| 12 | <!-- stroke-linecap examples --> |
| 13 | <line x1="20" y1="140" x2="100" y2="140" |
| 14 | stroke="#FF6B6B" stroke-width="12" stroke-linecap="round" /> |
| 15 | <line x1="20" y1="170" x2="100" y2="170" |
| 16 | stroke="#4FC3F7" stroke-width="12" stroke-linecap="square" /> |
| 17 | |
| 18 | <!-- Dashed stroke via CSS --> |
| 19 | <rect x="150" y="20" width="100" height="80" rx="10" |
| 20 | fill="none" stroke="#FFD93D" stroke-width="3" class="dashed" /> |
| 21 | |
| 22 | <!-- fill-rule example --> |
| 23 | <path d="M200,130 L220,170 L180,170Z M200,140 L210,160 L190,160Z" |
| 24 | fill="#C084FC" fill-rule="evenodd" opacity="0.8" /> |
| 25 | |
| 26 | <!-- Glow via filter --> |
| 27 | <circle cx="340" cy="60" r="40" fill="#00FF41" class="glow" /> |
| 28 | </svg> |
SVG gradients and patterns are defined in <defs> and referenced by ID. This keeps them reusable and keeps the markup clean.
| 1 | <svg viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <defs> |
| 3 | <!-- Linear gradient --> |
| 4 | <linearGradient id="lg" x1="0%" y1="0%" x2="100%" y2="0%"> |
| 5 | <stop offset="0%" stop-color="#00FF41" /> |
| 6 | <stop offset="50%" stop-color="#4FC3F7" /> |
| 7 | <stop offset="100%" stop-color="#C084FC" /> |
| 8 | </linearGradient> |
| 9 | |
| 10 | <!-- Radial gradient --> |
| 11 | <radialGradient id="rg" cx="50%" cy="50%" r="50%"> |
| 12 | <stop offset="0%" stop-color="#FFD93D" /> |
| 13 | <stop offset="100%" stop-color="#FF6B6B" /> |
| 14 | </radialGradient> |
| 15 | |
| 16 | <!-- Pattern --> |
| 17 | <pattern id="dots" patternUnits="userSpaceOnUse" |
| 18 | width="20" height="20"> |
| 19 | <circle cx="10" cy="10" r="4" fill="#00FF41" /> |
| 20 | </pattern> |
| 21 | </defs> |
| 22 | |
| 23 | <!-- Apply gradients --> |
| 24 | <rect x="20" y="20" width="160" height="80" rx="10" |
| 25 | fill="url(#lg)" /> |
| 26 | <circle cx="290" cy="60" r="50" fill="url(#rg)" /> |
| 27 | |
| 28 | <!-- Apply pattern --> |
| 29 | <rect x="20" y="120" width="360" height="60" rx="8" |
| 30 | fill="url(#dots)" /> |
| 31 | </svg> |
info
SVG text elements provide more layout control than HTML text, including the ability to position individual characters and render text along paths.
| 1 | <svg viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <!-- Basic text --> |
| 3 | <text x="20" y="40" fill="#00FF41" font-size="24" |
| 4 | font-family="monospace" font-weight="bold"> |
| 5 | SVG Text Rendering |
| 6 | </text> |
| 7 | |
| 8 | <!-- Text with tspan for mixed styles --> |
| 9 | <text x="20" y="80" fill="#A0A0A0" font-size="14" font-family="monospace"> |
| 10 | <tspan fill="#00FF41">SVG</tspan> supports |
| 11 | <tspan fill="#FFD93D" font-weight="bold">mixed</tspan> |
| 12 | <tspan fill="#4FC3F7" font-style="italic">styles</tspan> |
| 13 | <tspan dy="20" x="20" fill="#525252">and multi-line text.</tspan> |
| 14 | </text> |
| 15 | |
| 16 | <!-- Text along a path --> |
| 17 | <defs> |
| 18 | <path id="curve" d="M20,150 Q250,50 480,150" fill="none" /> |
| 19 | </defs> |
| 20 | <use href="#curve" stroke="#2A2A3E" stroke-dasharray="4,4" /> |
| 21 | <text font-family="monospace" font-size="14" fill="#C084FC"> |
| 22 | <textPath href="#curve"> |
| 23 | Text follows any SVG path — including curves and arcs |
| 24 | </textPath> |
| 25 | </text> |
| 26 | </svg> |
pro tip
SVG provides powerful mechanisms for organizing and reusing graphics. <g> groups elements, <defs> defines reusable assets, <use> instantiates them, and <symbol> creates standalone icons.
| 1 | <svg viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <defs> |
| 3 | <!-- Reusable icon definition --> |
| 4 | <g id="star"> |
| 5 | <polygon points="0,-10 3,-3 10,-3 5,2 7,10 0,5 -7,10 -5,2 -10,-3 -3,-3" |
| 6 | fill="#FFD93D" /> |
| 7 | </g> |
| 8 | |
| 9 | <!-- Symbol with viewBox (for icon systems) --> |
| 10 | <symbol id="icon-heart" viewBox="0 0 24 24"> |
| 11 | <path d="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5 |
| 12 | C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08 |
| 13 | C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5 |
| 14 | C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z" |
| 15 | fill="#FF6B6B" /> |
| 16 | </symbol> |
| 17 | </defs> |
| 18 | |
| 19 | <!-- Group --> |
| 20 | <g stroke="#FFFFFF" stroke-width="1" opacity="0.9"> |
| 21 | <circle cx="50" cy="50" r="20" fill="#4FC3F7" /> |
| 22 | <rect x="90" y="30" width="40" height="40" rx="5" fill="#00FF41" /> |
| 23 | </g> |
| 24 | |
| 25 | <!-- Use instances of the star --> |
| 26 | <use href="#star" x="200" y="30" /> |
| 27 | <use href="#star" x="250" y="50" transform="scale(1.5)" /> |
| 28 | <use href="#star" x="320" y="30" opacity="0.5" /> |
| 29 | |
| 30 | <!-- Symbol usage --> |
| 31 | <use href="#icon-heart" x="400" y="20" width="30" height="30" /> |
| 32 | <use href="#icon-heart" x="440" y="30" width="20" height="20" /> |
| 33 | </svg> |
The difference between <symbol> and <g> inside <defs>:
| Feature | <symbol> | <g> in <defs> |
|---|---|---|
| Has own viewBox | ✓ | — |
| Renders when used | ✓ | ✓ |
| Supports width/height on use | ✓ | — |
| Best for icon systems | ✓ | — |
| Hidden by default | ✓ | ✓ |
best practice
SVG transformations modify the coordinate system of an element or group. The transform attribute accepts multiple transformation functions.
| Function | Parameters | Description |
|---|---|---|
| translate | tx, ty | Moves element by offset |
| rotate | angle [, cx, cy] | Rotates around origin or given point |
| scale | sx [, sy] | Scales x and y axes |
| skewX | angle | Shear along x-axis |
| skewY | angle | Shear along y-axis |
| matrix | a, b, c, d, e, f | Full 2×3 affine transform matrix |
| 1 | <svg viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <!-- Original reference --> |
| 3 | <rect x="20" y="20" width="40" height="40" fill="#2A2A3E" /> |
| 4 | <text x="20" y="75" fill="#525252" font-size="10" font-family="monospace">Original</text> |
| 5 | |
| 6 | <!-- Translate --> |
| 7 | <g transform="translate(120, 20)"> |
| 8 | <rect x="0" y="0" width="40" height="40" fill="#00FF41" /> |
| 9 | <text x="0" y="55" fill="#A0A0A0" font-size="10" font-family="monospace">translate</text> |
| 10 | </g> |
| 11 | |
| 12 | <!-- Rotate --> |
| 13 | <g transform="translate(220, 40) rotate(45)"> |
| 14 | <rect x="-20" y="-20" width="40" height="40" fill="#4FC3F7" /> |
| 15 | <text x="-20" y="-30" fill="#A0A0A0" font-size="10" font-family="monospace">rotate</text> |
| 16 | </g> |
| 17 | |
| 18 | <!-- Scale --> |
| 19 | <g transform="translate(330, 10) scale(1.5)"> |
| 20 | <rect x="0" y="0" width="30" height="30" fill="#FFD93D" /> |
| 21 | <text x="0" y="45" fill="#A0A0A0" font-size="8" font-family="monospace">scale</text> |
| 22 | </g> |
| 23 | |
| 24 | <!-- Matrix --> |
| 25 | <g transform="matrix(1, 0.3, 0.2, 1, 400, 20)"> |
| 26 | <rect x="0" y="0" width="40" height="40" fill="#C084FC" /> |
| 27 | <text x="0" y="55" fill="#A0A0A0" font-size="10" font-family="monospace">matrix</text> |
| 28 | </g> |
| 29 | |
| 30 | <!-- Transform-origin (CSS) --> |
| 31 | <rect x="20" y="120" width="50" height="50" rx="5" |
| 32 | fill="#FF6B6B" style="transform-origin: 25px 25px; transform: rotate(15deg);" |
| 33 | /> |
| 34 | <text x="20" y="185" fill="#A0A0A0" font-size="10" font-family="monospace">CSS transform-origin</text> |
| 35 | </svg> |
info
SVG supports animation via SMIL (Synchronized Multimedia Integration Language) and CSS animations. SMIL is native to SVG and works without JavaScript.
| 1 | <svg viewBox="0 0 400 150" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <!-- animate — interpolate attribute over time --> |
| 3 | <circle cx="50" cy="75" r="20" fill="#00FF41"> |
| 4 | <animate |
| 5 | attributeName="cx" |
| 6 | from="50" to="350" |
| 7 | dur="3s" repeatCount="indefinite" |
| 8 | values="50; 350; 50" |
| 9 | keyTimes="0; 0.5; 1" /> |
| 10 | </circle> |
| 11 | |
| 12 | <!-- animateTransform — rotate continuously --> |
| 13 | <rect x="50" y="20" width="30" height="30" fill="#FFD93D"> |
| 14 | <animateTransform |
| 15 | attributeName="transform" |
| 16 | type="rotate" |
| 17 | from="0 65 35" to="360 65 35" |
| 18 | dur="2s" repeatCount="indefinite" /> |
| 19 | </rect> |
| 20 | |
| 21 | <!-- animateTransform — pulsing scale --> |
| 22 | <circle cx="300" cy="75" r="15" fill="#FF6B6B"> |
| 23 | <animateTransform |
| 24 | attributeName="transform" |
| 25 | type="scale" |
| 26 | values="1; 1.5; 1" |
| 27 | keyTimes="0; 0.5; 1" |
| 28 | dur="1s" repeatCount="indefinite" /> |
| 29 | </circle> |
| 30 | </svg> |
SVG elements can be animated with standard CSS animations and transitions, just like HTML elements. This is often more maintainable than SMIL for complex animations.
| 1 | <svg viewBox="0 0 400 150" xmlns="http://www.w3.org/2000/svg"> |
| 2 | <style> |
| 3 | .pulse { |
| 4 | animation: pulse 2s ease-in-out infinite; |
| 5 | transform-origin: center; |
| 6 | } |
| 7 | .bounce { |
| 8 | animation: bounce 1.5s ease-in-out infinite; |
| 9 | } |
| 10 | .fade { |
| 11 | animation: fade 3s ease-in-out infinite; |
| 12 | } |
| 13 | .spin { |
| 14 | animation: spin 3s linear infinite; |
| 15 | transform-origin: 350px 75px; |
| 16 | } |
| 17 | @keyframes pulse { |
| 18 | 0%, 100% { r: 15; opacity: 1; } |
| 19 | 50% { r: 25; opacity: 0.5; } |
| 20 | } |
| 21 | @keyframes bounce { |
| 22 | 0%, 100% { transform: translateY(0); } |
| 23 | 50% { transform: translateY(-30px); } |
| 24 | } |
| 25 | @keyframes fade { |
| 26 | 0%, 100% { opacity: 1; } |
| 27 | 50% { opacity: 0.2; } |
| 28 | } |
| 29 | @keyframes spin { |
| 30 | from { transform: rotate(0deg); } |
| 31 | to { transform: rotate(360deg); } |
| 32 | } |
| 33 | </style> |
| 34 | |
| 35 | <circle cx="60" cy="100" r="15" fill="#00FF41" class="pulse" /> |
| 36 | <rect x="130" y="80" width="30" height="30" rx="4" |
| 37 | fill="#4FC3F7" class="bounce" /> |
| 38 | <circle cx="230" cy="100" r="15" fill="#C084FC" class="fade" /> |
| 39 | <rect x="330" y="60" width="30" height="30" rx="4" |
| 40 | fill="#FFD93D" class="spin" /> |
| 41 | </svg> |
best practice
SVG scales infinitely without losing quality. The viewBox attribute defines a logical coordinate system, preserveAspectRatio controls how it fits the container, and omitting width/height makes SVG fluid.
| 1 | <!-- Fluid SVG — scales to container width --> |
| 2 | <svg viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg"> |
| 3 | <rect x="0" y="0" width="400" height="200" fill="#1A1A2E" rx="10" /> |
| 4 | <circle cx="200" cy="100" r="60" fill="#00FF41" opacity="0.3" /> |
| 5 | <text x="200" y="105" fill="#00FF41" font-size="24" |
| 6 | font-family="monospace" text-anchor="middle"> |
| 7 | Responsive SVG |
| 8 | </text> |
| 9 | </svg> |
| 10 | |
| 11 | <!-- Fixed size SVG --> |
| 12 | <svg viewBox="0 0 100 100" width="50" height="50" xmlns="..."> |
| 13 | <!-- Icon at fixed 50x50px --> |
| 14 | </svg> |
| 15 | |
| 16 | <!-- preserveAspectRatio options --> |
| 17 | <svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" |
| 18 | style="width: 100%; height: auto;"> |
| 19 | <!-- Fits within container, centered, maintaining aspect ratio --> |
| 20 | </svg> |
preserveAspectRatio combines alignment and meet/slice:
| Value | Behavior |
|---|---|
| xMidYMid meet | Fit entirely, centered (default) |
| xMinYMin meet | Fit entirely, top-left aligned |
| xMidYMid slice | Cover container, centered (crop excess) |
| none | Ignore aspect ratio, stretch to fill |
pro tip
SVG elements can be made accessible to screen readers through proper title, description, and ARIA attributes. This is critical for data visualizations, icons, and diagrams.
| 1 | <!-- Accessible chart --> |
| 2 | <svg viewBox="0 0 400 300" role="img" |
| 3 | aria-label="Bar chart showing Q1 sales: January $5k, February $7k, March $6k" |
| 4 | xmlns="http://www.w3.org/2000/svg"> |
| 5 | |
| 6 | <title>Q1 2026 Sales Report</title> |
| 7 | <desc> |
| 8 | Bar chart displaying monthly sales for the first quarter. |
| 9 | January: $5,000. February: $7,000. March: $6,000. |
| 10 | </desc> |
| 11 | |
| 12 | <!-- Bars with descriptive labels --> |
| 13 | <rect x="50" y="200" width="60" height="100" |
| 14 | fill="#00FF41" role="img" |
| 15 | aria-label="January: $5,000" /> |
| 16 | <rect x="150" y="140" width="60" height="160" |
| 17 | fill="#4FC3F7" role="img" |
| 18 | aria-label="February: $7,000" /> |
| 19 | <rect x="250" y="160" width="60" height="140" |
| 20 | fill="#C084FC" role="img" |
| 21 | aria-label="March: $6,000" /> |
| 22 | </svg> |
| 23 | |
| 24 | <!-- Icons should be hidden from screen readers --> |
| 25 | <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"> |
| 26 | <path d="..." /> |
| 27 | </svg> |
info
| 1 | <!-- Before: bloated (from vector editor) --> |
| 2 | <svg viewBox="0 0 100 100"> |
| 3 | <g id="Layer_1"> |
| 4 | <path d="M10,10 L90,10 L90,90 L10,90 Z" |
| 5 | fill="#00FF41" stroke="#000000" stroke-width="2"/> |
| 6 | </g> |
| 7 | </svg> |
| 8 | |
| 9 | <!-- After: optimized --> |
| 10 | <svg viewBox="0 0 100 100"> |
| 11 | <rect x="10" y="10" width="80" height="80" fill="#00FF41" /> |
| 12 | </svg> |
| 13 | |
| 14 | <!-- Icon sprite system --> |
| 15 | <svg xmlns="http://www.w3.org/2000/svg" style="display:none"> |
| 16 | <symbol id="icon-check" viewBox="0 0 24 24"> |
| 17 | <path d="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41-1.41Z"/> |
| 18 | </symbol> |
| 19 | <symbol id="icon-close" viewBox="0 0 24 24"> |
| 20 | <path d="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12Z"/> |
| 21 | </symbol> |
| 22 | </svg> |
| 23 | <svg viewBox="0 0 24 24" width="20" height="20"><use href="#icon-check"/></svg> |
Key optimization strategies:
best practice