SVG in HTML
Vector graphics that scale perfectly, weigh almost nothing and can be styled with CSS. Learn inline SVG, SVG as an image, and how to make one accessible.
- Concept
- Four ways to include one
- 1. Inline
- 2. As an image
- 3. As a CSS background
- 4. A sprite with use
- viewBox: the attribute that makes it responsive
- The shapes
- Accessibility
- Decorative
- Meaningful
- An icon inside a button
- Styling inline SVG
- A security note
- Important rules
- Common mistakes
- Best practices
- Practice
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
Concept
SVG - Scalable Vector Graphics - describes an image as shapes and coordinates rather than pixels. It scales to any size without loss, is usually smaller than an equivalent raster file, and when placed inline it becomes part of the DOM, so CSS and JavaScript can reach into it.
For logos, icons, diagrams, charts and any flat illustration, SVG is the correct choice.
Four ways to include one
1. Inline
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M3 12h18M12 3v18"/>
</svg>The graphic is part of the document. CSS can style it, scripts can animate it, and currentColor makes it inherit the surrounding text colour automatically - which is why an inline icon changes colour on hover with no extra work.
The cost is page weight and repetition: the same icon used forty times is forty copies of the markup.
2. As an image
<img src="/images/logo.svg" alt="Riverside College" width="140" height="40">Cached like any image, keeps the markup clean, and behaves exactly like a picture. The trade off is isolation: the page CSS cannot reach inside it, so a single colour icon cannot be recoloured from the stylesheet.
3. As a CSS background
.icon-search {
background-image: url("/icons/search.svg");
background-size: 20px 20px;
}For decoration only. A background image has no text alternative, so nothing meaningful may be delivered this way.
4. A sprite with use
<!-- defined once, hidden -->
<svg style="display:none">
<symbol id="icon-search" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M20 20l-4-4" stroke="currentColor" stroke-width="2"/>
</symbol>
</svg>
<!-- referenced anywhere, any number of times -->
<svg class="icon" aria-hidden="true"><use href="#icon-search"/></svg>One definition, many uses, and each use still inherits currentColor. This is the standard approach for an icon set.
viewBox: the attribute that makes it responsive
<svg viewBox="0 0 100 50" width="200" height="100">
<rect x="10" y="10" width="80" height="30" fill="#1e3a8a"/>
</svg>viewBox takes four numbers: minimum x, minimum y, width and height of the internal coordinate system. Everything drawn inside uses those coordinates, and the browser scales the result to whatever display size is set.
With a viewBox, the SVG scales fluidly. Without one, it is a fixed size box. Always include it.
The shapes
<svg viewBox="0 0 200 120">
<rect x="10" y="10" width="60" height="40" rx="6" fill="#dbeafe" stroke="#1e3a8a"/>
<circle cx="110" cy="30" r="20" fill="#dcfce7"/>
<ellipse cx="170" cy="30" rx="24" ry="16" fill="#fef3c7"/>
<line x1="10" y1="70" x2="190" y2="70" stroke="#94a3b8" stroke-width="2"/>
<polyline points="10,110 50,80 90,100 130,75" fill="none" stroke="#dc2626" stroke-width="2"/>
<polygon points="150,110 180,110 165,80" fill="#c4b5fd"/>
<path d="M10 60 Q 60 20, 110 60 T 190 60" fill="none" stroke="#0f172a"/>
<text x="10" y="20" font-size="12" fill="#0f172a">Label</text>
</svg>Text inside an SVG is real text: selectable, searchable, translatable and readable by a screen reader. That is a decisive advantage over canvas for anything with labels.
Accessibility
Decorative
<svg aria-hidden="true" focusable="false"><use href="#icon-search"/></svg>focusable="false" matters in older browsers, where an SVG could otherwise become a stray tab stop.
Meaningful
<svg role="img" viewBox="0 0 200 120" aria-labelledby="chart-title chart-desc">
<title id="chart-title">Bus ridership by year</title>
<desc id="chart-desc">Ridership rises steadily from 1.2 million in 2023 to 2.1 million in 2026.</desc>
<polyline points="..." fill="none" stroke="#1e3a8a" stroke-width="2"/>
</svg>title is the short name, desc the longer description. Both must be the first children, and role="img" makes the whole graphic a single announced object rather than a collection of shapes.
An icon inside a button
<button type="button" aria-label="Search">
<svg aria-hidden="true" focusable="false"><use href="#icon-search"/></svg>
</button>The icon is hidden and the button carries the name. An icon only button with neither is announced as button and nothing more.
Styling inline SVG
.icon {
width: 1.25em;
height: 1.25em;
fill: currentColor; /* inherit the text colour */
vertical-align: -0.15em; /* sit on the text baseline */
}
button:hover .icon { fill: #1e3a8a; }Sizing icons in em ties them to the surrounding font size, so they scale with the text automatically.
A security note
An SVG file can contain scripts and external references. Never accept an uploaded SVG and serve it back inline without sanitising it - it is an execution vector in the same way an HTML upload would be. Serving user uploaded SVG through an img element neutralises scripts in current browsers, but sanitising is still the correct step.
Important rules
- Always include
viewBox. - SVG uses
fillandstroke, notcolorandborder. - Inline SVG can be styled by page CSS; an SVG in an
imgcannot. titleanddescmust be the first children of the element they describe.- Text in SVG is real text.
- An
imgpointing at an SVG needsaltlike any other image.
Common mistakes
- Omitting
viewBox, leaving a graphic that will not scale. - Pasting a huge editor exported SVG inline, complete with metadata and comments.
- Repeating the same inline icon dozens of times instead of using a sprite.
- Icon only buttons with no accessible name.
- Expecting CSS to style an SVG loaded through
img. - Serving user uploaded SVG inline without sanitising.
- Using a PNG for a logo when an SVG would be sharper and smaller.
Best practices
- Optimise exported SVG before shipping; editor output is typically several times larger than necessary.
- Use a sprite with
usefor icon sets. - Use
currentColorso icons follow the text. - Size icons in
em. - Mark decorative graphics
aria-hidden="true" focusable="false". - Give meaningful graphics a
title, adescandrole="img". - Prefer SVG over icon fonts, which break when the font fails to load.
Practice
- Draw a simple logo inline with a
viewBoxand confirm it stays sharp at three hundred percent zoom. - Build an icon sprite with three symbols and use each twice.
- Make an icon inherit the text colour with
currentColorand change on hover. - Add
title,descandrole="img"to a chart and listen to it with a screen reader.