Slides are available at
https://jaypanoz.github.io/ebookcraft2017/
Good developers are lazy.
That’s why I’ve implemented a ‘Tweet my Speech’ feature.
Workshop materials can be downloaded at
https://github.com/JayPanoz/ebookcraft2017/
This is probably my last ebook conf so I want it to be fun.
Everything I know
I learned during side projects.
Current good practices are practices in need of a disruption.
Bringing responsiveness to EPUB without media queries
If you’re into comics…
A ton of knowledge.
Want more?
Libraries are bad, frameworks are evil! Real devs do without the pathetic tools we have!!! Real Web Developer
Frameworks and libraries deal with
They can make an impact
Just use jQuery. Stack Overflow
You might not need jQuery. The Modern Web
(youmightnotneedjquery.com)
Javascript improved
because jQuery proved
there was a better way to do it.
A ton of knowledge…
for the whole community.
The stronger the community,
the greater the knowledge,
the better the tooling.
That’s why I’m here today.
❤️
Any sufficiently advanced technology is indistinguishable from magic. Arthur C. Clarke
Here is the process
We must get familiar with the critical rendering path.
An object representation of your document.
Nodes are created from elements and text.
An object representation of the styles associated with the DOM.
CSS is a render blocking resource:
the Render Tree cannot be constructed without first fully parsing the CSS.
Scripts in which you append contents, change styles, add eventListeners for interactions, etc.
JS is a parser blocking resource:
the parsing of the HTML document itself is blocked by JavaScript.
A representation of the elements
to be rendered on the page.
DOM Tree + CSSOM Tree + JS alterations
The size of the viewport.
It provides a context for CSS styles
which are dependent on it.
Visible elements of your document
are converted to pixels.
(The size of the DOM and some styles
can slow painting down.)
Just go out and talk to a tree. Make friends with it. Bob Ross
This applies to modern EPUB apps…
We make a lot of detours, but we’re always heading for the same destination. Paulo Coelho
Parser and render blocking resources.
Think of an EPUB app as a scenic route: it adds detours to the rendering path.
Reading Systems don’t override for the sake of it,
overrides solve issues.
.calibre > div, .calibre1 > div {
position: static !important;
}
/* centering hack to support Calibre-generated vertical centered documents */
:root:not([__ibooks_has_multiple_pages])
*[__ibooks_centering_hack^="horizontal-"] {
min-width: {{.pageWidth}}px;
}
:root:not([__ibooks_has_multiple_pages])
*[__ibooks_centering_hack^="vertical-"] {
min-height: {{.pageHeight}}px;
}
/* fix documents that abuse inline-block */
:root[__ibooks_has_multiple_pages]
*[__ibooks_has_inline_block] {
display: block !important;
}
CSS Hacks come with great responsibility.
Some “hacks” are utter abuse
/* Scrollable frame solution for FXL
1. In Object export, enter "subchapter" as epub:type
2. Add this snippet to your CSS
*/
div[*|type = "subchapter"] {
position: relative;
}
div[*|type = "subchapter"] > div {
overflow: auto;
}
Other stuff you should know
iBooks is all about perceived performance.
Your performance budget is pretty tight.
This impacts ebook design dramatically.
EPUB is a spectrum.
There are different ways to manipulate contents.
One more thing…
It’s hardware that makes a machine fast. It’s software that makes a fast machine slow. Craig Bruce
Have you heard about EPUB files crashing iBooks? Friend
Your #eprdctn computer
will bite you in the arse.
The Honor 5X is one of the best lower-priced large-screen smartphones available. The Guardian
Cores | CPU | RAM | |
---|---|---|---|
Mac Mini | 2 | 2.8Ghz | 16GB |
iPad Mini 2 | 2 | 1.3Ghz | 1GB |
Honor 5x | 8 | 1.5Ghz | 2GB |
Your laptop is a filthy liar. Alex Russell
(Google Chrome software engineer)
The mobile issues we must pay attention to:
That’s a non issue, right?
EPUB files are stored locally, right?
Loading a webpage is much more than shipping bytes down the wire. Once the browser has downloaded our page’s scripts it then has to parse, interpret and run them. Addy Osmani
(Staff Engineer at Google)
Flash not really better than good old spinning metal.
Expect more or less the perf of the best HDDs.
big.LITTLE
Low power cores are used aggressively,
High power cores are used infrequently.
Score | Blow | |
---|---|---|
Mac Mini | 174.68 | |
iPad Mini 2 | 55.712 | -68% |
Honor 5x | 20.796 | -88% |
Ops/sec | Blow | |
---|---|---|
Mac Mini | 43,224,096 | |
iPad Mini 2 | 15,405,748 | -64% |
Honor 5x | 2,725,418 | -94% |
Your mobile device is
a filthy liar too. Benchy McBenchmark
Ops/sec | Blow | |
---|---|---|
Mac Mini | 43,224,096 | |
iPad Mini 2 | 15,405,748 | -64% |
Honor 5x (liar) | 2,725,418 | -94% |
Honor 5x (honest) | 1,749,414 | -96% |
Recent iPhones and iPads
will bite you in the arse too.
Torture numbers and they’ll confess to anything. Gregg Easterbrook
Mobile is Hostile
Cores | CPU | RAM | |
---|---|---|---|
Mac Mini | 2 | 2.8Ghz | 16GB |
iPad Mini 2 | 2 | 1.3Ghz | 1GB |
Honor 5x | 8 | 1.5Ghz | 2GB |
High-end eReader | 1 | 1Ghz | 512MB |
EPUB is a spectrum.
There is no average,
there are extremes.
I’m a killjoy.
You’re gonna kiss the sun and taste the motherfuckin’ rainbow. Elmo
Progressive enhancement is
starting with a rock-solid foundation
Progressive enhancement is
starting with a rock-solid foundation
and then
adding enhancements to it.
EPUB is a spectrum.
Reading Systems provide
a range of capabilities.
@supports
Feature Queries
aka the best thing that
ever happened to EPUB
(Sorry @dauwhe)
@supports (property: value) {
selector {
property: value;
}
}
@supports not (prop1: value1) {
selector {
prop2: value2;
}
}
@supports (prop1: value1) or (prop3: value3) {
selector {
prop1: value1;
prop3: value3;
}
}
@supports (prop4: value4) and (prop5: value5) {
selector {
prop4: value4;
prop5: value5;
}
}
@supports (initial-letter: 3 2) {
.first-para:first-letter {
initial-letter: 3 2;
}
}
@supports (transform: rotate(1deg) translateX(-1%)) {
.journal-titre .rotate-1 {
display: block;
transform: rotate(-1deg);
}
.journal-titre .rotate-2 {
display: block;
transform: rotate(1deg);
}
.journal-titre .rotate-3 {
display: block;
transform: rotate(-1deg) translateX(-2%);
}
.journal-titre .rotate-4 {
display: block;
transform: rotate(-3deg) translateY(-0.2em);
}
}
@supports (font-variant-caps: small-caps) {
body {
font-variant: oldstyle-nums proportional-nums;
}
.small-caps {
font-variant-caps: small-caps;
}
}
element {
float: left;
}
@supports (shape-outside: {value}) {
element {
shape-outside: {value};
clip-path: {value};
}
}
@supports (height: calc(98vh - 5em)) {
img {
width: auto;
max-width: 100%;
min-height: 300px;
height: calc(98vh - 5em);
max-height: 95%;
object-fit: contain;
}
}
A dynamic typescale, based on the viewport
h1 {
font-size: calc(1em + 3vmin);
}
h2 {
font-size: calc(1em + 2vmin);
}
h3 {
font-size: calc(1em + 1vmin);
}
In theory, it’s simple and beautiful, it solves a lot of issues, including user settings.
In practice, iBooks scales vmin
as well…
Why the fuck did you do that! Jules
Float to full-width
.float {
min-width: 40%;
max-width: 100%;
width: calc((30em - 100%) * 1000);
}
@supports (display: flex) {
parent {
min-height: 95vh;
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
@supports (display: flex) {
.grid {
display: flex;
flex-wrap: wrap;
flex: 1 1 15em;
}
.grid li {
page-break-inside: avoid;
}
}
* Sorry Laura, github’s URLs are case-sensitive.
if (feature) { /* do something */ }
(It’s like @supports
but for JS)
Taking static resources and turning them into dynamic interactions.
Building optional features which can
improve the reading experience.
JavaScript can deal with the painful stuff…
like tables.
Lots of people think JavaScript
is evil when it comes to a11y.
The truth is, JavaScript can
improve a11y dramatically.
What’s happening here?
Progressive enhancements make books progressive.
Stop designing for the lowest common denominator,
that’s self-inflicted pain.
It looks like a lost cause but if we do things well who knows what could happen? Luis Enrique
(Coach of the FC Barcelona team which
defeated PSG 6–1 after losing 4–0)
Patterns and widgets a community creates and uses become de facto standards.
Vendors can’t ignore
de facto standards.
We’re currently letting them set and have complete control over those.
Knowledge is power. France is Bacon
It’s a little recipe I use in emergencies. Mac Gyver
Leverage CSS and JS
A project by frenchman Gaël Poupard.
We don’t have oil,
but we have ideas. Valéry Giscard d’Estaing
It’s just a CSS file…
warning developers about possible accessibility risks and mistakes that exist in HTML code.
img[alt=""] {
outline: 4px solid gold;
}
img[alt=""] ~::after {
content: "Empty [alt] attribute. This is only okay for decorative images. Is it a decorative image?";
}
A ton of knowledge
This will blow your mind
column-width
column-gap
Hint
html {
-webkit-column-width: {{.pageWidth}}px;
-webkit-column-gap: {{.gutter}}px;
width: {{.width}}px;
height: {{.pageHeight}}px;
}
Any volunteer?
(Come on, don’t be shy)
html.iBooksPreviewer-iPadLandscape {
box-sizing: border-box;
width: 1024px;
height: 768px;
margin: 0;
padding: 88px 61px 61px 61px;
overflow-x: auto;
-webkit-column-width: 422px;
-webkit-column-gap: 58px;
column-width: 422px;
column-gap: 58px;
column-fill: auto;
}
.iBooksPreviewer-iPadLandscape > body {
margin: 0 !important;
}
.iBooksPreviewer-day {
background-color: #fafbfa !important;
color: #000000 !important;
}
.iBooksPreviewer-sepia {
-webkit-filter: sepia(100%) contrast(0.95);
filter: sepia(100%) contrast(0.95);
}
.iBooksPreviewer-gray {
background-color: #5a5a5c !important;
color: #ffffff !important;
}
.iBooksPreviewer-night {
background-color: #121212 !important;
color: #b1b1b1 !important;
}
.iBooksPreviewer-gray a,
.iBooksPreviewer-night a {
color: #55beff !important;
-webkit-text-fill-color: #55beff !important;
}
.iBooksPreviewer-baselineHelper {
background-image: -webkit-linear-gradient(top, rgba(122,122,122,0) 92%,rgba(122,122,122,0.6) 100%);
background-image: linear-gradient(to bottom, rgba(122,122,122,0) 92%,rgba(122,122,122,0.6) 100%);
background-size: 100% 1.5em;
background-position: top 0.25em left 0;
}
alert()
If my calculations are correct […] you’re gonna see some serious shit. Doc Brown
console.log()
The console already exists,
you have to plug it into the DOM.
Gentlepeople, start your Search engine
(The answer is on Stack Overflow)
var logger = document.getElementById('logger');
['log','warn','error'].forEach(function (verb) {
console[verb] = (function (method, verb, log) {
return function (text) {
method(text);
var msg = document.createElement('span');
msg.classList.add(verb);
msg.textContent = verb + ': ' + text;
logger.appendChild(msg);
};
})(console[verb].bind(console), verb, logger);
});
function printDom() {
var dom = document.documentElement.outerHTML;
console.log(dom);
}
function getStyle(element, cssProp) {
var styleLog,
cssValue = window.getComputedStyle(element, null).getPropertyValue(cssProp),
tagName = element.tagName.toLowerCase();
styleLog = tagName + " \{ " + cssProp + ": " + cssValue + "; \}";
console.log(styleLog);
}
var customStyles = ["font-family", "font-size", "line-height"];
function getCustomStyles(element) {
var customStylesLog,
cssObj = window.getComputedStyle(element, null),
tagName = element.tagName.toLowerCase();
customStylesLog = tagName + " \{";
for (var i = 0; i < customStyles.length; i++) {
var cssObjProp = customStyles[i];
customStylesLog += "\n " + cssObjProp + ": " + cssObj.getPropertyValue(cssObjProp) + ";";
}
customStylesLog += "\n\}";
console.log(customStylesLog);
}
It’s simplistic, it’s not elegant, you could so much more, much more efficiently… It’s pure crap! Real Web Developer
Shit you build
will be a lot more useful than
elegant tools you don’t use.
You’ll acquire the necessary knowledge to understand the over-engineered tools you didn’t use.
First do it, then do it better.
OMG I dit it! I survived @JiminyPan’s workshop!!!
God help us, we’re in the hands of engineers. Ian Malcom
epub:type
pre
+ its styles via JSCores | CPU | RAM | |
---|---|---|---|
Kobo Aura One | 1 | 1Ghz | 512MB |
Kindle Oasis | 1 | 1Ghz | 512MB |
Nook Glowlight+ | 1 | 1Ghz | 512MB |
Read | Write | |
---|---|---|
Mac Mini (FD) | 715.5 | 430.7 |
Mac Mini (HDD) | 104 | 103 |
iPad Mini 2 | 121 | 64.6 |
Honor 5x (int.) | 125 | 49.49 |
Honor 5x (ext.) | 128.58 | 46.96 |
Score | Blow | |
---|---|---|
Mac Mini | 406.98 | |
iPad Mini 2 | 64.16 | -84% |
Honor 5x | 17.80 | -96% |
jQuery | JS | Boost | |
---|---|---|---|
Mac Mini | 3,375,112 | 43,224,096 | 1181% |
iPad Mini 2 | 1,237,461 | 15,405,748 | 1145% |
Honor 5x | 204,505 | 1,749,414 | 755% |