Embedding Complex SVGs Into HTML

(AKA Crazy shit we did to make SVG work for us)

Cameron Lakenen – Box

The Box View API (formerly Crocodoc) is a service for generating portable, web-viewable versions of documents Documents are converted into HTML5 and viewed in the browser using Viewer.js
We combine three web standards to render documents:

Why SVG?

*Can't you do everything with HTML + CSS?*

Strokes and Fills

Clipping, Masking, and Blending

Rendering Quality and Zooming

Vector graphics scale infinitely (excluding rasterized images)

External Assets

The Dreaded Spinner

Embed Methods

  • inline SVG (true inline vs DOMParser)

The humble <img> tag


<img> tag: no external assets

SVGs loaded via <img> won't fetch external assets


<img> tag: no external assets

Solution: base64-encode all assets into nested data: urls

  • Very complex
  • Memory issues and crashing on mobile devices

Embed methods

<img> is difficult at best – let's look at our other options:

  • inline SVG

Inline SVG

Inline SVG is part of the [HTML 5 spec](http://www.w3.org/html/wg/drafts/html/master/single-page.html#svg)!

IE 9+

DOMParser !== inline SVG*

  • Inline SVG (HTML, SVG text parsed on page load) is very fast
  • Document viewer - pages are loaded dynamically
  • SVG embedded with JS is not parsed asynchronously (yet**)
*at least not in Chrome/Blink, and likely not in any browsers currently
**http://crbug.com/308321 and http://crbug.com/308768

Inline (DOMParser)


Iframe VS Inline (DOMParser)

Embed methods

Inline SVG performance isn't quite there yet

  • inline SVG

Iframe vs Object vs Embed

Effectively the same thing in most browsers

## Basic embed via iframe/object * Spinner :( * Can't modify text before loading ```html <iframe type="text/svg+xml" src="page-1.svg"></iframe> <object type="text/svg+xml" data="page-1.svg"></object> ```


Embed object as a tiny SVG that contains a bit of JS

// proxy-svg.js

function proxyScript() {
    /* proxy JS code */

var SVG = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg">' +
    '<script><![CDATA[(' + proxyScript.toString() + ')()]]></script>' +

var object = document.createElement('object');
object.type = 'image/svg+xml';
object.data = 'data:image/svg+xml;base64,' + window.btoa(SVG);







## Proxy-SVG * Too complicated * Doesn't work in IE (no scripts in data:urls)
## document.write() * Create an empty `<iframe src="">` * `document.write()` writes SVG directly into iframe

## document.write() * Works very well in Chrome and IE * Works in FF/Safari, minus `<defs>` bug * Causes spinner in FF

"Direct Proxy"

  • Combination of Proxy-SVG and document.write() methods
  • Safari - create an iframe, write a script with document.write()
  • Firefox - create an object with data:url encoded script
  • Call script directly from parent window (viewer.js)
## "Direct Proxy"

## "Direct Proxy" - Firefox

## "Direct Proxy" - Safari

## "Direct Proxy" * Solves the `<defs>` bug in FF/Safari * No spinner in Firefox!
# Questions?