Let’s talk about eBook performance

If you’re not an eBook producer, this article probably won’t interest you.

As a matter of fact, even if you are, chances are you’ve already experienced painful performance but it’s not something we’re used to speak about so there’s little interest anyway.

Now, if we take a look at the web, performance is everywhere: good performance is a must since it’s part of the user experience, a 3-second delay may cause a dramatic drop in sales, developers try to hit 60 frames per second and so on and so forth.

How many of us, eBook producers, actually have a precise idea of mobile apps’ or eInk Readers’ performance? Can you list CSS or JS bottlenecks? Do you define rules or best practices based on performance? Do you know how Reading Systems work? Really?

I surely can’t answer those questions in an extensive manner. And you probably can’t either because the lack of debug tools is baffling. So it’s all about testing on a shitload of devices and feeling what doesn’t work well, taking decisions reactively thus wasting a lot of time.

Since I’ve been doing this extensively for the last year, let’s share some useful info.

Should I do eBookCraft 2017, this will be one of my first slides (© José Luiz Bernardes Ribeiro / CC BY-SA 3.0)

Mobile is Hell

Welcome!
Please be informed performance on mobile devices is abysmal.
Enjoy your stay and happy apocalypse!

Listen, I’m not saying eInk readers are low end devices but some of the RS they’re using (e.g. RMSDK) certainly makes you feel like it’s low end…

And problem is it can even be worse on cheap Android devices. If you’ve never QA-ed a fixed-layout file on a $200 Android phone, please be informed it is just unusable, not so much because fixed dimensions provide a crappy UX “à la PDF” but because performance (rendering, interactions…) is just plain terrible.

Truth is it’s not much better with iOS’ Webkit and this is why Kobo or Google are using an image-based fixed-layout reader when possible, say for comics.

To sum things up, you should design your project with a very tight performance budget. In other words, the performance you’ll get with iBooks is by no means representative of the average performance you’ll get across the ecosystem, you should consider it a maximum — if you need a minimum, Adobe Digital Editions on Android is the app you’re searching for since it can’t even display a whole page on a low end device while it’s just an image.

From experience, if you get OK-but-not-so-great-perf in iBooks, it will be absolute crap on an awful lot of devices and apps, even iOS’. You must achieve stellar performance in iBooks, no less!

Please append that previous node to head.

Obviously, this means you should also never trust the almighty desktop.

Obvious bottlenecks

  • Images’ loading and rendering are expensive, optimize those ones.
  • Same for SVG. Have no mercy!
  • Fonts impact your performance budget quite dramatically on low end devices, use fonts only when needed and always subset them.
  • The bigger the xhtml file, the crappier the perf, especially if you’ve got a lot of images in there. Divide and conquer.
  • Finally, don’t bloat your markup with useless tags and shit. It might make a tiny difference but it can sometimes save your arse.

CSS bottlenecks

Yeah, I Know, what could go wrong with CSS, right?

Actually, a lot. And I discovered that when designing the Blitz framework, which explains its functional CSS approach.

Let’s talk about selectors’ performance:

  1. tag, #id, .class and :pseudo-class have good performance;
  2. [attribute=“stuff”], [attribute~=“stuff”], [attribute^=“stuff”], etc. have abysmal performance.

For your information, the formers can be 5 times more performant on desktop and 10 times more performant in a mobile webview than the latters. You can launch this stress test if you don’t believe me.

And don’t forget we’ve got an additional toll to pay in eBooks i.e. the extra RS layer which may be a big fucking JavaScript file and a default CSS. And if the mobile app is using a webview, that’s an extra factor to take into account: performance is getting better but it’s easy to mess up. Unluckily, you could be a victim of collateral damage…

So, to sum up, use the cascade to your advantage and design reusable classes, don’t repeat yourself and don’t “scope” classes to tags like InDesign’s output. Period.

Don’t use

[class="stuff"] {…}
[epub|type~="stuff"] {…}

if you don’t need to. Don’t overqualify selectors e.g.

.class > ol.class > li {…}

if possible.

Of course it depends on how you use them, a few exceptions won’t make a huge difference but if your whole CSS is designed around those selectors, they will cripple performance big time once bottlenecks are piling up.

And then there are properties and values…

If you want to kill legacy RMSDK’s performance, float and opacity are the surest props to do so.

Too many floats or opacity in an xhtml file and it might take 4–5 seconds to turn a page in not-so-old eInk Readers. I’m shitting you not. Needless to say it’s terrible UX.

Finally, if you’re into CSS 3 animations, read this HTML5rocks tutorial. TL;DR: use transforms (+ opacity) for high performance, avoid props affecting layout (bad) and paint (worst).

Which leads us to… interactive stuff.

JS bottlenecks

Once again, keep in mind RS can be a big fucking pile of JavaScript, which implies your scripts affect theirs.

As a consequence, it’s quite easy to achieve crappy perf in reflowable text by displaying/hiding contents for instance — which is discouraged in vendor’s specs anyway because they didn’t foresee the need to update pagination at the author’s level….

As we’ve seen, repaint is expensive. If you can make it happen without the props affecting repaint (color, visibility, background, etc.), just do it… even if it means re-designing your widget so that it works in a different manner. Else, try to repaint sparingly. Check your performance budget!

As regards JavaScript…

If you know JavaScript and can do without jQuery or plugins, please go vanilla JavaScript. Seriously.

Firstly, don’t forget jQuery is an additional layer of abstraction: you’re not manipulating raw DOM elements but jQuery objects. So you might have to deal with two nested layers of abstraction depending on the RS implementation. And this can make a perceivable difference—ever wondered why iBooks devs are providing a specific iBooks.js framework?

Secondly, JavaScript is now pretty great to use (just take a look at ES 2015) and it’s the best way to avoid performance issues — as long as you don’t create memory leaks. As a matter of fact, there are few arguments in favour of jQuery based on what we’re mostly doing in eBooks — and nope, your lack of desire to learn JavaScript is not a solid argument, especially as it can skyrocket your productivity.

Once you start animating a rather large amount of elements on a page and you load the whole freaking jQuery lib + a plugin, I can guarantee some apps won’t even be able to keep on painting.

Also, don’t repeat your script in each XHTML file (won’t be cached) and don’t force a manual initialization if not necessary; you’ll save a few precious milliseconds which might make a visible difference in budget-constrained RS.

Should you really need jQuery, please load a custom subset because that’s an extra 250 Kb unsubsetted. And don’t forget to minify. Or maybe try alternative frameworks?

When profiling JS, don’t forget it’s not just about JavaScript but everything JS-related (images, layers, etc.)

Conclusion

All those pieces of advice are relative. It all comes down to your performance budget and user’s perception. I know optimizing requires a lot of time you don’t necessarily have… so let’s say that as long as it feels smooth, it’s OK.

User’s perception is also why you should test your file the hell out, on various devices, from low to high end. Don’t fall into the trap of implementing for one single RS though, iBooks is notorious for crashing quite easily on 1st-gen Retina devices if you don’t optimize your JS like a maniac for instance… and you might not notice it.

It should be repeated for the benefit of everyone, the perf you’ll get in iBooks or in ADE/Readium desktop is not the perf you’ll get everywhere.

We all know — at least I hope we all know — that we should optimize (images and SVG) subset (fonts) and minify (JS and CSS) because “it’s best practice”. But performance is a lot more than subsetting and minifying, it’s designing and implementing with performance in mind.

Minifying won’t help if your CSS and JS are badly designed. Subsetting jQuery won’t help if you’re loading it just to toggle classes, something which is not so difficult with plain old JavaScript — get elements in document, add eventListeners, toggle in classList.

Performance is not an afterthought, it’s a main objective. And I hope I have convinced you that you should care.