Embedding SVGs - Mastering SVG For Responsive Web Design - Responsive Web Design, Part 1 (2015)

Responsive Web Design, Part 1 (2015)

Mastering SVG For Responsive Web Design

Embedding SVGs

There are six ways to embed an SVG in a page, each with its advantages and disadvantages. You choose the embedding technique depending on how you’re going to use the SVG and whether you need to script and style it after embedding.

An SVG can be embedded in one of the following ways:

1. As an image using the <img> element:

<img src="mySVG.svg" alt="" />

2. As a background image in CSS:

.el {background-image: url(mySVG.svg);}

3. As an object using the <object> element:

<object type="image/svg+xml" data="mySVG.svg"><!-- fallback here --></object>

4. As an iframe using an <iframe> element:

<iframe src="mySVG.svg"><!-- fallback here --></iframe>

5. Using the <embed> element:

<embed type="image/svg+xml" src="mySVG.svg" />

6. Inline using the <svg> element:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" … >

<!-- svg content -->

</svg>

USING <OBJECT>

The <object> element is the primary way to include an external SVG file. The main advantage of using this element is that there is a standard mechanism for providing an image (or text) fallback if the SVG is not rendered. If the SVG cannot be displayed for any reason — perhaps the specified URI is wrong — the browser will display the content between the opening and closing <object> tags.

<object type="image/svg+xml" data="mySVG.svg">

<img src="fallback-image.png" alt="…" />

</object>

If you intend to use any advanced SVG features such as CSS and scripting, the HTML5 <object> element is your best option.

You will probably want to fall back to a raster version of the SVG image using the <img> tag, as we did in the previous example. However, providing fallback this way has a bad consequence: browsers that support SVG will request both the SVG and the fallback image, resulting in an unnecessary extra HTTP request.

In order to avoid the double requests problem, you can provide the PNG fallback image as a background image in CSS rather than as a foreground image in HTML. To provide the fallback as a background image, instead of adding <img> between the opening and closing <object> tags, you would insert a <div> and then set the fallback image as a background image for the <div>:

<object id="logo" type="image/svg+xml" data="logo.svg">

<div></div>

</object>

#logo div {

background-image: url(path/to/fallback/logo.png);

/* other styles here */

}

This workaround is used by the folks of Clearleft; David Bushell wrote about it in a primer to SVG19 that he published on his blog.

Browsers supporting SVG will display the SVG referenced in <object> and the <div> will neither be displayed nor styled, thus avoiding the request for the PNG background image. Only if the browser does not support SVG does the <div> inside it get rendered and styled with the fallback PNG.

USING <IFRAME>

Since browsers can render SVG documents in their own right, it is possible to embed and display an SVG using an iframe. This may be a good method if you want to completely separate SVG code and script from your main page. However, manipulating an SVG image from your main page’s JavaScript becomes a little more difficult, and is subject to the same origin policy, which permits running your scripts on the iframe only if the iframe and your main page originate from the main site. You can read more about the same origin policy on Wikipedia20.

The <iframe> element, just like the <object> element, comes with a default way for providing fallback for browsers that don’t support SVG between the opening and closing <iframe> tags.

USING <EMBED>

While it was non-standard in the past, the <embed> element is today a part of the WHATWG HTML Living Standard and the HTML5 Candidate Recommendation. Its purpose is to include content that needs an external plugin to work. The Adobe Flash plugin requires the use of <embed> and supporting it is the only real reason for its use with SVG. The <embed> element has no default fallback mechanism.

USING <IMG> AND CSS

Like any other image format, an SVG can be embedded using an <img> element. It can also be embedded as a background image in CSS.

Unfortunately, an SVG embedded as an image using either of these techniques cannot be interacted with, whether using CSS (e.g. hover interactions) or JavaScript (e.g. click interactions, etc.).

Moreover, the contents of the SVG cannot be selected and styled from the style sheet because the SVG is in another document and styles don’t apply across documents. This is also why SVGs referenced externally in any of the other previously mentioned embedding techniques cannot be styled using CSS from the main page.

That said, if you are using a CSS preprocessor like LESS or Sass you may be able to modify an SVG’s background fill color. Zach Schnackel wrote about a technique that uses LESS to do it21 that you can check out.

Even though the contents of the SVG cannot be selected with CSS, you can still style an SVG image and change its overall styles and colors using CSS filters. An SVG image is an image, after all. And just as we can apply CSS filters to bitmap images, we can do the same to SVG images as well.

Using CSS filter functions like grayscale(), saturation() and hue-rotate() among others, you can change the color, saturation, brightness and even blurriness of an SVG image. Multiple filters can be used by chaining them together, resulting in even more diverse effects. You can then use CSS transitions and animations to animate the style changes using these filters.

Animations do work in an SVG embedded as using <img> or embedded as a background image, but only if they are defined inside the root <svg>.

Generally speaking, pretty much everything that applies to an SVG embedded as a background image in CSS also applies to an SVG embedded using an <img> tag, CSS- and JavaScript-wise.

EMBEDDING SVGS INLINE

An SVG can also be embedded in a document inline — as a “code island” — using the <svg> element. Today, this is one of the most popular ways for embedding SVGs. Working with an inline SVG and CSS becomes a lot easier, as the SVG can be styled and animated by targeting it using style rules placed anywhere in the document — the styles don’t need to be included between the opening and closing <svg> tags to work. On the other hand, the other techniques require the CSS styles and animations to be present inside the <svg>.

If you embed the SVG inline and apply the styles inside the SVG in a <style> block, these styles will affect other inline SVGs in the document. That is, if you have two <svg> elements in your page, and each of them has an element with an ID #paw, then if the first <svg> has styles applied to the element #paw, these styles will also be applied to the #paw element in the second <svg> — unless, of course, these styles are explicitly overridden. The takeaway here is that styles inside an inline <svg> can affect elements inside another <svg> in the same document.

Embedding SVGs as code islands in the HTML is a good choice, as long as you’re willing to add to the size of the page or give up backwards compatibility, since there is no default fallback mechanism. In addition, an inline SVG cannot be cached, and hence will require the same amount of time to render and load with every visit, unlike an image referenced using <img>. That adds an extra HTTP request, but browsers can then take advantage of their default caching to speed up any subsequent loads. That said, it is generally a good idea to serve resources with far-future Expires headers. You can do that by adding or changing a few lines in your website’s .htaccess file. The HTML5 Boilerplate .htaccess22 contains a lot of excellent ready-to-use snippets; among these snippets, you can find the few lines that specify the cache times of different file types, including media types.

# ----------------------------------------------------------------------

# | Expires header |

# ----------------------------------------------------------------------

# Serve resources with far-future expires headers.

#

# (!) If you don’t control versioning with filename-based

# cache busting, you should consider lowering the cache times

# to something like one week.

#

# https://httpd.apache.org/docs/current/mod/mod_expires.html

<IfModule mod_expires.c>

ExpiresActive on

ExpiresDefault "access plus 1 month"

# CSS

ExpiresByType text/css "access plus 1 year"

# ... more file types and configurations here ...

# Media files

ExpiresByType audio/ogg "access plus 1 month"

ExpiresByType image/bmp "access plus 1 month"

ExpiresByType image/gif "access plus 1 month"

ExpiresByType image/jpeg "access plus 1 month"

ExpiresByType image/png "access plus 1 month"

ExpiresByType image/svg+xml "access plus 1 month"

ExpiresByType video/mp4 "access plus 1 month"

ExpiresByType video/ogg "access plus 1 month"

ExpiresByType video/webm "access plus 1 month"

# ... more file types and configurations ...

Notice the image/svg+xml type included in the snippet.

You are likely to come across a lot of inline SVG implementations. Some of these implementations include the SVG xmlns (XML namespace) attribute on the root <svg> and some don’t. The truth of the matter is that if you embed your SVG inline in an HTML5 document, the xmlns attribute is no longer required.

The way you embed your SVG will affect any CSS and JavaScript animations and interactions that you may apply later. As a rule of thumb, SVG-as-image (an SVG embedded using an img tag or as a CSS background image) cannot be interacted with, and so any hover or click interactions, for example, will not work. CSS animations will only work if they are defined inside the root <svg> element. The <object>, <iframe>, and <embed> elements require CSS animations and interactions to be defined inside the <svg> as well, because styles do not apply across documents. And an SVG embedded inline can be interacted with and animated no matter where the animations and interactions are defined.

In addition to these six techniques, you can also embed the SVG image using the <picture> element, which also provides you with a default way for providing fallback to non-supporting browsers in many different ways. You should read all about using the <picture> element in Yoav’s chapter (see part 2 of this book).