When I wrote the “book” The Greatest CSS Tricks Vol. I, I put “book” in quotes because there wasn’t anything terribly book-like about it. The only way you could read it was online, logged into this website, with an MVP supporter membership. No printed version, not even digital copies you might expect from a digital book.

I’ve changed that now and offer PDF and EPUB versions of the book. They are free downloads for members — just add them to your cart and check out.

All this book-writing stuff was and is an experiment. I like writing on this website in a blog-post-like format where all the content is at URLs and can have interactive content. Being digital, I can control the access and such. It means I can write in a way that is comfortable to me, and maybe-just-maybe, I can be more prolific about it. Maybe I can get a Vol. II done that I already have a ton of ideas for. Maybe I can write some other books I’ve been thinking about. Now I have a system! A place to write, multiple places to publish to, and a way to sell it.

Producing the digital versions

When I originally made the choice to write the book online, I figured PDF would be incredibly simple. I’d output the content on a “raw” template (just as a clean starting point that will last and is easy to preview), apply nice print-like CSS, then quite literally, just ⌘P (Print) and “Save as PDF.” Done.

Print dialog bog in Google Chrome, with the Save as PDF option chosen.

That actually kinda works. You can fiddle with the settings (e.g. “✔ Print Background Graphics” in order to have white text on a dark background on things like code blocks) and get it fairly nice. But there are issues — like you can’t control the header or footer of each page very well. Not to mention it’s not programmatic, but a very manual process.

Doing things programmatically is what I was shooting for. Then I happened across this blog post from Baldur Bjarnason in which he was looking for work:

• Do you need to make a site or sites that walks like a book, talks like a book, and reads like a book but everything you make looks like a blog?

• Are you having trouble dealing with file formats such as PDF, DOCX, or EPUB using web tech?

• Are you trying to produce PDFs or ebooks from your website or your CMS?

Yes, yes, yes!

Programatically creating an eBook

I reached out to Baldur and he was able to help me work on all this. He created an automated system for me that accepts a local .html file and automatically produces PDF, EPUB, and MOBI formats from that single file. Essentially, I can run make from the command line and it’ll do all the work, leveraging open source tools.

VS Code showing there terminal open running a Makefile script producing the eBooks.

I still needed near-perfect HTML ready for the machine, though, which took some work. Fortunately, I was already somewhat ready to produce this, as I have a special URL that outputs the raw content (you can still see this if you’re not a member, just with truncated content) with the light print styles I wanted.

The tools

With the raw HTML and a programmatic approach in hand, here are the tools that make up the stack:

  • For PDF creation, we tried both Paged.js and WeasyPrint. They both had their quirks and did things worse/better than each other. We ultimately landed on Paged.js.
  • For EPUB creation, we used pandoc.
  • For MOBI creation (which we did not focus on at all), we used Calibre. It’s a native Mac app, but it has an ebook-convert tool buried within it that can be called from the command line.

To get to the point where we could use these tools over the command line, all sorts of other software have to be installed and ready to use, like Python, pango, libffi, and more. Baldur’s script made managing this easy, which was awesome.

It looks like there is a new player on the block called Percollate) for this stuff, but we did not explore that.

An Public Repo Combining all this Tooling for HTML-to-eBook Creation

After we got through this process together, Baldur generously created an open-source trimmed down public repo (book-tricks) for all y’alls reference. There is a lot of useful magic in this Makefile that I’d be shocked if it wasn’t useful for someone in the same position I was in: needing to create eBooks from simple HTML.

Previewing builds

PDFs are easy to view, of course (you can even just use a web browser), but I generally popped it open in Preview.app.

EPUB is similarly easy on a Mac because you can just pop it into Books.app to view it.

Mac app Books.app with the EPUB version of the book open.

For MOBI, Calibre’s main function is viewing those, so that’s the trick there:

The most painful part is the feedback loop. There is a whole process of updating code (mostly CSS) and then running the whole build to see how it all looks. I’m sure I did it 100 or more times to get things right. There really should be a better story for this, with live previews.

Web-only vs. eBook-only content

Early in the book-writing process, I had given up on both paper and digital versions. I stopped leaning on images in the text as much and started using embedded CodePen demos to show off output and code. That’s the ideal experience for the web anyway. But I can’t use embedded Pens in eBooks. eBooks can do some interactive things (e.g. EPUB supports animated GIFs and links, of course), but running JavaScript and using <iframe>s are things I didn’t want to count on. If I had proper images for everything, then just maybe it’s more ready for paper someday anyway.

It’s easy enough to hide things from the eBook output with display: none, so that’s what I did for all embedded Pens. (They are a bit of HTML before they transform into the iframe.) Then to have “alternate” content that is only for the eBook version, I essentially just wrapped that stuff in <div class="print-only"> which is hidden online and shown in the print CSS. I made custom blocks in the WordPress block editor to make authoring those blocks easier. That way, I could really see what I was doing.

One interesting bit is that because I was shooting for eBook-only here, I didn’t have to do the sort of CSS trickery I’m used to for things like print stylesheets where the output is likely some computer paper. For example, in a print stylesheet, I’d probably normally do:

main a[href]::after { content: " (" attr(href) ") ";
}

That way, people can see the URLs of links in content. But with these digital eBooks, I just make sure the links are blue and they’ll be clickable in any of the digital formats.


This was a fun journey! I’m mostly excited to have climbed the ladder of understanding a bit on all this, especially because rendering things on digital canvases is kinda my wheelhouse. I’m only a couple of rungs up though, as this stuff has a pretty steep learning curve!

Similar Posts