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

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 fill and stroke, not color and border.
  • Inline SVG can be styled by page CSS; an SVG in an img cannot.
  • title and desc must be the first children of the element they describe.
  • Text in SVG is real text.
  • An img pointing at an SVG needs alt like 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 use for icon sets.
  • Use currentColor so icons follow the text.
  • Size icons in em.
  • Mark decorative graphics aria-hidden="true" focusable="false".
  • Give meaningful graphics a title, a desc and role="img".
  • Prefer SVG over icon fonts, which break when the font fails to load.

Practice

  1. Draw a simple logo inline with a viewBox and confirm it stays sharp at three hundred percent zoom.
  2. Build an icon sprite with three symbols and use each twice.
  3. Make an icon inherit the text colour with currentColor and change on hover.
  4. Add title, desc and role="img" to a chart and listen to it with a screen reader.

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All HTML notes →
HTML

The canvas Element

A blank bitmap you draw on with JavaScript. Powerful for graphics and games, and invisible to every reader who cannot see the screen.

Read more
HTML

The template Element

Markup that is parsed but not rendered, waiting to be cloned. The clean way to build repeated content in JavaScript without writing HTML as strings.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.