An SVG that looks fine in the editor and falls apart on the page is usually an embedding problem, not a file problem. The browser handles the same graphic differently depending on whether it arrives through img, object, iframe, embed, a CSS background-image or pasted-in inline markup.
MDN’s SVG as an image guide documents the split. Load the file through img or a CSS background and scripts and external resources are blocked. Load it through iframe, object or embed and both keep working. Only inline markup gives page CSS and DOM scripts direct access.
Ways to Embed SVG in HTML Compared
Five of the methods load a separate .svg file. Inline markup is the odd one out, since it puts the graphic straight into the DOM.
A scalable vector graphic stays sharp at any size, so what you’re really choosing is how much control the page gets and what that costs in requests and caching.
| Method | CSS from the page | JavaScript access | Requests and caching |
|---|---|---|---|
| img and background-image | No, styles live inside the file | None | One request, cached separately |
| Inline svg | Full | Direct DOM access | No extra request, cached with the HTML |
| object and embed | No | Same-origin only | One request, cached separately |
| iframe | No | Same-origin only | One request, cached separately |
A data URI sits closest to the first group. The file content lives inside the src or url() value, so it needs no request, but it is cached only with the page or stylesheet that holds it.
Inline is the only method where the page has full control. The rest hand the browser a closed file.
Embedding SVG With img, CSS Background-Image and Data URIs
The img tag, a CSS background-image and a data URI all treat the SVG as a picture instead of a document. Every limit below follows from that one fact.
On the plus side, the browser caches the file separately, so later pages load it faster. The syntax is familiar, alt text included, and making the image a link is a matter of nesting img inside an a element.
The downsides add up faster:
- JavaScript can’t touch the graphic
- The page’s CSS can’t restyle it, so colors and rules have to live inside the file
- Pseudo-classes like
:focusdo nothing - Scripts are disabled, and external resources such as stylesheets never load
That last limit comes from MDN’s SVG as an image guide, which applies it to image contexts only. The same file loaded through iframe, object or embed keeps its scripts and external resources.
The img tag
Point src at the file and give the image a size. MDN requires a height or width, or both when the SVG has no inherent aspect ratio.
<img src="logo.svg" alt="Acme logo" width="120" height="40">Content graphics need real alt text. Decorative ones take alt="" so screen readers skip them.
CSS background-image
Section dividers, repeating patterns and other decoration are what this method suits. Anything that carries meaning belongs elsewhere, because a background has no alt text.
.divider {
background-image: url("wave.svg");
background-repeat: no-repeat;
background-size: cover;
}MDN’s vector graphics tutorial confirms that background SVGs follow the same CSS and JavaScript limits as img.
Data URIs
A data URI puts the SVG text inside the src or url() value, so the graphic costs no separate request.
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Ccircle cx='5' cy='5' r='4' fill='tomato'/%3E%3C/svg%3E" alt="Red dot">- Keep
xmlns, because the data URI is a standalone document - Single quotes inside the markup stop it from closing the attribute early
- Encode
#as%23, or the browser reads it as a fragment and cuts the markup - The angle brackets get percent-encoded too, as in the sample
- Skip base64 for SVG, since it only lengthens text that is already text
As of MDN’s August 2026 update to the use element page, loading a data URI through use href is deprecated for security reasons. Data URIs belong in img and CSS, not in sprites.
How to Add Inline SVG to an HTML Page
Paste the svg element straight into the HTML body. There’s no file reference and no extra request, and every shape becomes an element the page can reach.
Steps for inline SVG
- Open the .svg file in a text editor and copy everything from the opening
svgtag to the closing one. - Delete any XML prolog or DOCTYPE above the
svgtag. They belong in standalone files, not HTML pages. - Paste the markup inside
body, where the graphic should render. - Keep the
viewBox, then setwidthandheightor size the graphic in CSS. - Add
role="img"and atitleelement as the first child so assistive technology announces it. - Reload and inspect the page in Chrome DevTools to confirm the shapes show up in the DOM.
<svg viewBox="0 0 100 100" role="img" aria-labelledby="dot-title">
<title id="dot-title">Red dot</title>
<circle cx="50" cy="50" r="40" fill="tomato" />
</svg>The xmlns attribute trips people up. MDN’s inline examples carry none, and Can I use lists the HTML5 parser as the only requirement. A standalone .svg file is an XML document, though, so that one does need xmlns="http://www.w3.org/2000/svg".
Leaving the attribute in pasted markup does no harm.
Reusing icons with symbol and use
Define each icon once as a symbol, then stamp it out with use.
<svg width="0" height="0" style="position:absolute">
<symbol id="icon-search" viewBox="0 0 24 24">
<circle cx="10" cy="10" r="6" fill="none" stroke="currentColor" stroke-width="2" />
<path d="M15 15l6 6" stroke="currentColor" stroke-width="2" />
</symbol>
</svg>
<svg class="icon" width="24" height="24">
<use href="#icon-search"></use>
</svg>- Use
href, notxlink:href, which SVG 2 deprecated - Point
hrefat an external file (sprite.svg#icon-search) to cache the sprite separately - Same-origin rules apply, since browsers may refuse a cross-origin
hrefand no cross-origin policy can be set foruse - CSS inheritance has to be requested explicitly, because the cloned nodes are not guaranteed to inherit CSS properties on their own (MDN)
What inline SVG costs
Inline SVG saves one HTTP request and takes styling through class and id. CSS interactions like :focus work, so does CSS animation, and linking the graphic only needs the markup wrapped in a.
The costs are real, though. The graphic suits only one location without duplication, the HTML file grows, and the browser cannot cache the markup like a regular image asset. A fallback inside foreignObject still downloads its images in browsers that support SVG.
For small graphics the page has to control, inline is the right call.
When Do object, iframe and embed Make Sense for SVG?
Rarely. Reach for object when a same-origin SVG needs script access plus a fallback, use iframe when the file needs isolation, and skip embed.
The object element
Set type="image/svg+xml" and point data at the file path. MDN requires at least one of data and type.
<object type="image/svg+xml" data="diagram.svg" width="400" height="300">
<img src="diagram.png" alt="Architecture diagram">
</object>- Fallback content between the tags shows when the resource fails to load
- Same-origin scripts reach the SVG through
contentDocument - The page’s CSS still cannot restyle the shapes inside
The iframe element
The sandbox attribute isolates the file from the page, and that is the main reason to pick iframe. The catch is fallback content, which appears only in browsers without iframe support, not when the image fails to load (MDN). Scripts on the main page reach the SVG only when both share an origin.
<iframe src="diagram.svg" width="400" height="300" title="Architecture diagram" sandbox></iframe>Sources disagree on this element. A 2006 tutorial by Tiffany B. Brown carries a later note naming iframe as the current best practice, while MDN calls it definitely not the best method.
The embed element
An embed can’t hold fallback content, and it has none of the loading controls iframe offers.
Its width and height must be absolute values, because percentages are not allowed. Modern browsers dropped plug-ins, which was the reason this element existed.
Skip it.
Where the standards discussion stands
MDN’s object page (updated April 2026) and embed page (updated September 2026) both mark the elements as widely available. In WHATWG HTML issue 7037, the maintainer annevk wrote that both elements probably need to be deprecated.
The same issue explains the sizing quirk. A test case there shows object sizing its box from the SVG’s aspect ratio but laying the graphic out like an iframe, because object and embed create a nested browsing context for SVG (otherwise getSVGDocument() would not work).
Inline SVG or an External File: Which Should You Use?
Inline the SVG when the page has to style or script it. Link it as a file when it only needs to appear, and especially when the same artwork repeats across pages.
Browser support doesn’t separate the two. Can I use lists 97.49% global usage for inline SVG and the same 97.49% for SVG in img (2026 data, built on StatCounter shares).
Most cases come down to a few questions.
- Does the page change the graphic? Hover colors, CSS animation and script-driven updates all need inline markup.
- Does it repeat across pages? A file is cached once and reused, while inline markup travels inside every HTML response.
- How big is it? Large markup inflates the HTML and can’t be cached on its own.
MDN describes inline SVG as saving an HTTP request, and also as uncacheable like a regular image asset. Read together, those two points mean inlining pays off for small graphics and becomes a cost for large ones that repeat.
Inlining everything is the common reflex. It backfires on large illustrations that appear on many pages.
A mixed setup works well: img for large artwork, inline SVG for icons that change color, and a symbol sprite when one icon appears many times.
How to Style and Script Embedded SVG
Inline SVG responds to CSS selectors and DOM scripting like any HTML element. Embedded documents need a second route in, and img offers none.
CSS color, hover and animation
Set fill: currentColor on the shapes and the icon inherits the text color of its parent. One rule on the parent then recolors it.
.icon path { fill: currentColor; }
.btn:hover { color: tomato; }A presentation attribute such as fill="red" loses to any CSS rule, so a stylesheet can overrule the colors baked into exported markup.
You can animate SVG with CSS keyframes on transform, opacity and stroke-dashoffset.
SMIL is the other route, with the animate, animateTransform and set elements keeping the animation inside the markup. GSAP is worth a look for sequenced timelines that keyframes make awkward.
JavaScript on inline SVG
Inline SVG nodes answer to the same DOM methods as HTML. Listeners and attribute changes need nothing beyond plain JavaScript.
const dot = document.querySelector("#dot");
dot.addEventListener("click", () => dot.setAttribute("r", 30));New nodes need the SVG namespace. document.createElementNS("http://www.w3.org/2000/svg", "rect") builds a real SVG element, while createElement("rect") builds an unknown HTML element that never draws.
Scripting an embedded SVG document
object, iframe and embed each hold a separate document, so scripts reach the graphic through the element.
contentDocumentoniframeandobjectreturns the SVG document, which MDN’s scripting guide calls the best way ingetSVGDocument()exists on all three elements and returns anXMLDocument, ornullwhen the element does not hold SVG- From inside the SVG file,
parent.functionName()calls a page function
Read the document only after the element’s load event, because earlier calls return nothing useful.
The old window.svgDocument shortcut from Adobe’s SVG Viewer does not exist in Mozilla’s native implementation, so skip it.
How to Size an Embedded SVG So It Scales
Keep the viewBox and let CSS control the rendered size. The viewBox defines the drawing’s own coordinate system, and the browser scales it to whatever box the page provides.
It takes four numbers in the order min-x min-y width height, separated by whitespace or commas. MDN stresses that the rectangle maps to the SVG viewport, not the browser viewport.
The same shape reads very differently under different values, because user units resolve against the viewBox size:
viewBox="0 0 100 100"turns a circle withr="4"into a small dotviewBox="0 0 10 10"makes that same circle nearly fill the graphic
A negative min-x or min-y shifts the origin.
To fit a responsive design, drop fixed width and height from inline markup and size the graphic in CSS.
svg { width: 100%; max-width: 480px; height: auto; }| preserveAspectRatio | Behavior | Fits |
|---|---|---|
| xMidYMid meet (default) | Whole viewBox visible, centered | Logos, icons |
| xMidYMid slice | Viewport covered, overflow cropped | Decorative banners |
| none | Stretches unevenly, meet and slice ignored | Bars, rules, fills |
| xMinYMin meet | Pinned to the top left corner | Corner-anchored art |
Without a viewBox, preserveAspectRatio has no effect on scaling (MDN). And a viewBox width or height of 0 or less disables rendering entirely.
How to Make Embedded SVG Accessible
Content graphics need an accessible name, and decorative ones should be hidden from assistive technology. The markup depends on the embedding method.
Inline SVG: title, desc and ARIA
Short names go in title and long explanations in desc, and MDN says neither renders on screen. Browsers may show the title text as a tooltip on hover.
<svg viewBox="0 0 200 100" role="img" aria-labelledby="chart-title chart-desc">
<title id="chart-title">Quarterly sales</title>
<desc id="chart-desc">Bar chart: sales rise in each of the four quarters.</desc>
<rect x="10" y="60" width="30" height="40" />
</svg>MDN prefers listing both ids in aria-labelledby, because assistive technology supports it better than aria-describedby. When aria-describedby is present, it takes precedence over desc.
The accessible SVG files guide goes deeper on these patterns.
Text drawn with the text element stays readable to assistive technology and search engines, while text converted to outlines does not.
Other embedding methods
For object, put an img with alt between the tags as fallback content. An iframe or embed needs a title attribute, and MDN warns that without one, screen reader users cannot tell what the embedded content is. With img, the alt attribute carries the whole name, and there’s no long-description slot.
Decorative graphics
Use alt="" on img.
On inline svg, aria-hidden="true" does the job. It is a standard ARIA state that removes the graphic from the accessibility tree.
Never hide a graphic that is the only carrier of meaning.
How to Shrink and Secure SVG Before Embedding
Exported SVGs should go through SVGO before they reach a page. Anything you didn’t write yourself needs sanitizing too, which closes a script-injection route.
MDN notes that files exported from Inkscape have great room for size reduction. A dedicated SVG optimization pass removes it.
Shrinking the file with SVGO
SVGO is a Node.js library and command-line tool that strips editor metadata, comments, hidden elements and default values without changing how the graphic renders (svgo.dev, 2026).
npm install -g svgo
svgo logo.svg -o logo.min.svgIt needs Node.js 16 or later. SVGOMG, linked from the SVGO site, gives the same cleanup in a browser interface.
The default preset runs 33 plugins, and a few of them can quietly break the output if you leave the defaults alone.
removeViewBoxis opt-in, and adding it stops SVGs from scaling, so they clip or fail to fill their containerremoveDescruns by default but only deletes empty or editor-attribution descriptions, whileremoveAny: truedeletes every accessible descriptioncleanupIdsshortens or drops ids it cannot see referenced inside the file, so turn it off for sprite sheets (svgo.dev’s own override example disables it)
Sanitizing untrusted SVG
Inline SVG runs scripts. Any SVG from users, forms or third parties must pass through a sanitizer before it enters the DOM.
DOMPurify, a DOM-only sanitizer for HTML, MathML and SVG, is at version 3.4.14 as of this writing and has been developed since February 2014.
DOMPurify.sanitize('<svg><g/onload=alert(2)//<p>');
// becomes <svg><g></g></svg>
DOMPurify.sanitize(dirty, { USE_PROFILES: { svg: true, svgFilters: true } });The second call keeps only safe SVG elements and SVG filters, per the DOMPurify README.
- Sanitize last, since editing the markup afterward can void the sanitization
- Legacy browsers such as MSIE get no protection, because DOMPurify returns the input unchanged there (check
DOMPurify.isSupported) - On a server, pair it with a current jsdom, since the README rates happy-dom as not safe
Uploaded .svg files need the same care. MDN says the image-mode script block applies to image contexts only, so the same file opened directly in a tab keeps its scripts. Show uploads through img, or sanitize them at upload.
Why Is an Embedded SVG Not Showing?
Start with the Content-Type response header. MDN calls server misconfiguration a very common reason for SVG failing to load, and Firefox then shows the markup as text or garbled output.
A plain .svg file should come back with these headers.
Content-Type: image/svg+xml
Vary: Accept-EncodingA gzip-compressed .svgz file adds Content-Encoding: gzip. Without that header it loads as encoded noise, so use .svgz only on servers configured for it.
- Open the file URL directly in a browser tab. A 404 means the path is wrong, and relative paths break when the page URL changes depth.
- Open DevTools, select the SVG request in the Network tab and compare the response headers with the block above.
- Check standalone files for
xmlnson the rootsvgand for a stray DOCTYPE, which MDN says to leave off. - Inspect the element in Chrome DevTools. A 0 x 0 computed box points to missing dimensions or a collapsed parent container.
- Confirm no optimizer plugin removed the
viewBox. - For
object,iframeandembed, wait for theloadevent before readingcontentDocument.
If the file renders in its own tab but loses fonts, images or styles under img, it depends on external resources that image mode blocks.
Inline SVG never touches the server, so headers don’t apply. A blank inline graphic points to its own markup, its size or the CSS around it.
Embedding SVG in HTML FAQ
What does SVG stand for?
The letters stand for Scalable Vector Graphics, an XML-based language for describing vector images. Embedding means placing that graphic in a page, either as markup inside the HTML or as a file the page references.
Does Google index SVG images?
Yes, when the file loads through img. Google Search Central documentation (updated March 2026) lists SVG among the formats supported in an img src, and it states that Google does not index CSS images.
For inline SVG, add a title element so the graphic carries a text description.
Can WordPress upload SVG files?
Not by default. WordPress rejects the file with a message that the type is not permitted for security reasons, and WordPress core Trac ticket 53100 shows that adding svg to the allowed MIME types (for example through the upload_mimes filter) is required to lift the block.
That step inspects nothing inside the file, so pair it with a sanitizing plugin such as Safe SVG.
Can you lazy load an SVG?
For file-based methods, yes. Add loading="lazy" to the img tag, together with width and height, because MDN warns that unloaded images count as 0 by 0 and may never intersect the viewport.
Inline SVG sits inside the HTML itself, so it has no loading attribute.
How do you add a fallback for browsers that cannot show SVG?
Put a PNG in the img src and the SVG in srcset. Only browsers that understand srcset load the SVG, so older ones keep the PNG.
MDN names IE 8 and below and Android 2.3 and below as the browsers this protects. In CSS, declare the PNG as background first, then the SVG as background-image.
How to Verify Embedded SVG Before Launch
Before launch, each graphic should render, scale and carry an accessible name, and the order of those checks matters.
- Response headers and file path
- Size and viewBox at phone and desktop widths
- Accessible name in the DevTools accessibility tree
A graphic that fails to load cannot be measured or named, so a header or path fault blocks the most and costs the least to find. Scaling comes second because a fixed size without a viewBox clips or overflows once the container shrinks.
Files that fail the sizing check need repair at the source, and editing SVG files covers that work.
Verified in October 2026, this sequence stays valid unless the WHATWG deprecates object and embed or browsers tighten use href loading further.
- What is Backend in Web Development? - September 13, 2026
- What is Frontend Development? - September 11, 2026
- How to Make a Button in Figma: Design Best Practices - September 10, 2026


