You don't need external assets in an HTML file


(Written mostly to settle a good-natured disagreement.)

One of the great advantages of HTML is that it can call on external resources. Your index.html can load a style.css and display a picture.jpg. But... it doesn't have to use external resources.

(I know this isn't news to some of you - but everyone has to start somewhere.)

Here are three techniques for inlining external assets.

Easy Mode

The normal way of adding a stylesheet to HTML is something like:

HTML HTML<link rel="stylesheet" type="text/css" href="whatever.css">

That loads an external resource. You don't have to do it like that though. Inside your HTML document, you can write:

HTML HTML<style type="text/css">
body {
   background-color:#f00;
}
</style>

Similarly, for JavaScript, the normal mode of writing is:

HTML HTML<script src="whatever.js"></script>

But, again, you can inline all your JavaScript:

HTML HTML<script>
   alert("hi!");
</script>

Easy-peasy! Let's go for something a bit more difficult.

Hard Mode

Let's say we want to include a fancy webfont in our page. Normally, our CSS would contain something like this:

CSS CSS@font-face {
    font-family: 'whatever';
    src: url('whatever.woff2') format('woff2');
}

But URLs can be Base64 Encoded. This is a clever way of turning binary data into something suitable for including inline in a text file. This means, rather than calling an external URl for the font, we can place the entire contents of the font file inside the HTML file. Like this:

CSS CSS@font-face {
    font-family: 'whatever';
    src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgABAAAAACdkABIAAAAAVNAAACcBAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP0ZGVE0cGh4bjDwcIAZgAINaCBoJhGURCAr9CPFrC4IEAAE2AiQDhAQEIAWHYgeDUgx+G/FMBcd1twORKPRvOypqglyVHhzXYeMgQM/HZP...==) format('woff2');
}

The same is true with every external resource you might want to use. For example, here's what a normal image looks like in HTML:

HTML HTML<img src="whatever.gif" alt="Animation of a cute kitten yawning." />

And here it is, inlined with Base64:

HTML HTML<img src="data:image/gif;base64,R0l....." alt="Animation of a cute kitten yawning." />

The entire image file - every single byte - is converted into Base64 and written inside the HTML document. The browser doesn't load it from an external file. If your Internet connection disappears, you can still load the image.

Magic! OK, let's go one step further...

Extreme Mode

How about if we take all of our external resources and compress them into a single .zip file. And then inline that file into an HTML document. And then use JavaScript to extract that compressed file to render directly in the browser.

Sounds ridiculous, but it is possible!

SingleFileZ is a library which does just that. Visit the demo site and save the page. You'll get a single HTML file. Disconnect from the Internet and open the HTML file. It will automatically display as per normal. If you're feeling adverturous, rename the .html file to .zip and you'll be able to unzip it.

Downloading it

If you're in control of your server, or you can set the HTTP headers, it's possible to set the Content Disposition to tell the browser to download and save a file rather than rendering it in the browser:

 TXTContent-Disposition: attachment; filename="whatever.html"

If not, you can use the HTML5 Download attribute in your markup:

HTML HTML<a href="whatever.html" download="whatever.html">Download the file</a>

Try it now!

What have we learned today

It's possible to create a single, self-contained HTML file which contains CSS, JS, Fonts, Images, and anything else you would normally load externally.


Share this post on…

  • Mastodon
  • Facebook
  • LinkedIn
  • BlueSky
  • Threads
  • Reddit
  • HackerNews
  • Lobsters
  • WhatsApp
  • Telegram

8 thoughts on “You don't need external assets in an HTML file”

  1. Another technique would be to use something like https://github.com/jonathantneal/posthtml-inline-assets along with PostHTML to take a 'standard' HTML document and then inline things like CSS, JavaScript, turn image src values into data URIs, turn SVG sprite links into inlined SVGs etc. PostHTML is a great tool for certain kinds of work and I think it deserves a bit more recognition compared to its big sibling PostCSS!

    Reply
  2. Doc Oct says:

    I use a Chrome extension called something like "Save Page WE" that does all these tricks so I can save an article to a single html file on my hard drive. It's been pretty nice to have. Every once in a while it won't get everything though, I have to check it. I think it's the lazy loading images on some sites. It doesn't do the zip file trick, that's a neat idea. Would help to save some space since Base64 tends to increase file sizes by 33%.

    Reply
  3. John says:

    I use a FF extension called SingleFile that does this. However on the saved page images are encoded as base64, and are set at the size used in the page, even though on the site that image may be clicked to view a larger size. Videos also don't play at all on the saved page.

    Reply

What links here from around this blog?

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.

Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">