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
<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
<style type="text/css">
body {
background-color:#f00;
}
</style>
Similarly, for JavaScript, the normal mode of writing is:
HTML
<script src="whatever.js"></script>
But, again, you can inline all your JavaScript:
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
@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
@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
<img src="whatever.gif" alt="Animation of a cute kitten yawning." />
And here it is, inlined with Base64:
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
<a href="whatever.html" download="whatever.html">Download the file</a>
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.
Not if you want to adhere to best practices for Content Security Policy though…
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!Nice article! By the way, there’s ongoing work to standardize this feature as Web Bundles: web.dev/web-bundles/.
Gildas says:
Author of SingleFileZ here, thank you very much for the article!
You don't need external assets in an HTML file shkspr.mobi/blog/2021/08/y… (news.ycombinator.com/item?id=280554…)
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%.
You don't need external assets in an HTML file said on :
This Article was mentioned on css-tricks.com
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.