A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="en">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Portable EPUBs (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Is that even respected? Retrospectively? What a shAItshow…
  28. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  29. <meta name="robots" content="noai, noimageai">
  30. <!-- Documented, feel free to shoot an email. -->
  31. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  32. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  36. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  37. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  38. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  39. <script>
  40. function toggleTheme(themeName) {
  41. document.documentElement.classList.toggle(
  42. 'forced-dark',
  43. themeName === 'dark'
  44. )
  45. document.documentElement.classList.toggle(
  46. 'forced-light',
  47. themeName === 'light'
  48. )
  49. }
  50. const selectedTheme = localStorage.getItem('theme')
  51. if (selectedTheme !== 'undefined') {
  52. toggleTheme(selectedTheme)
  53. }
  54. </script>
  55. <meta name="robots" content="noindex, nofollow">
  56. <meta content="origin-when-cross-origin" name="referrer">
  57. <!-- Canonical URL for SEO purposes -->
  58. <link rel="canonical" href="https://willcrichton.net/notes/portable-epubs/">
  59. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  60. <article>
  61. <header>
  62. <h1>Portable EPUBs</h1>
  63. </header>
  64. <nav>
  65. <p class="center">
  66. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  67. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  68. </svg> Accueil</a> •
  69. <a href="https://willcrichton.net/notes/portable-epubs/" title="Lien vers le contenu original">Source originale</a>
  70. <br>
  71. Mis en cache le 2024-01-25
  72. </p>
  73. </nav>
  74. <hr>
  75. <p>Despite decades of advances in document rendering technology, most of the world's documents are stuck in the 1990s due to the limitations of PDF. Yet, modern document formats like HTML have yet to provide a competitive alternative to PDF. This post explores why this is the case, and proposes a way forward based on the EPUB format.</p>
  76. <h2>The Good and Bad of PDF</h2>
  77. <p>PDF is the de facto file format for reading and sharing digital documents like papers, textbooks, and flyers. People use the PDF format for several reasons:</p>
  78. <ul>
  79. <li>PDFs are self-contained. A PDF is a single file that contains all the images, fonts, and other data needed to render it. It's easy to pass around a PDF. A PDF is unlikely to be missing some critical dependency on your computer.</li>
  80. <li>PDFs are rendered consistently. A PDF specifies precisely how it should be rendered, so a PDF author can be confident that a reader will see the same document under any conditions.</li>
  81. <li>PDFs are stable over time. PDFs from decades ago still render the same today. PDFs have a relatively stable standard. PDFs cannot be easily edited.</li>
  82. </ul>
  83. <p>Yet, in the 32 years since the initial release of PDF, a lot has changed. People print out documents less and less. People use phones, tablets, and e-readers to read digital documents. The internet happened; web browsers now provide a platform for rendering rich documents. These changes have laid bare the limitations of PDF:</p>
  84. <ul>
  85. <li>PDFs cannot easily adapt to different screen sizes. Most PDFs are designed to mimic 8.5x11" paper (or worse, 145,161 km2). These PDFs are readable on a computer monitor, but they are less readable on a tablet, and far less readable on a phone.</li>
  86. <li>PDFs cannot be easily understood by programs. A plain PDF is just a scattered sequence of lines and characters. For accessibility, screen readers may not know which order to read through the text. For data extraction, scraping tables out of a PDF is an open area of research.</li>
  87. <li>PDFs cannot easily express interaction. PDFs were primarily designed as static documents that cannot react to user input beyond filling in forms.</li>
  88. </ul>
  89. <p>These pros and cons can be traced back to one key fact: the PDF representation of a document is fundamentally unstructured. A PDF consists of commands like:</p>
  90. <ul>
  91. <li>Move the cursor to the right by 0.5 inches.</li>
  92. <li>Set the current font color to black.</li>
  93. <li>Draw the text "Hello World" at the current position.</li>
  94. </ul>
  95. <p>PDF commands are unstructured because a document's organization is only clear to a person looking at the rendered document, and not clear from the commands themselves. Reflowing, accessibility, data extraction, and interaction all rely on programmatically understanding the structure of a document. Hence, these aspects are not easy to integrate with PDFs.</p>
  96. <p>This raises the question: how can we design digital documents with the benefits of PDFs but without the limitations?</p>
  97. <h2>Can't We Just Fix PDF?</h2>
  98. <p>A simple answer is to improve the PDF format. After all, we already have billions of PDFs — why reinvent the wheel?</p>
  99. <p>The designers of PDF are well aware of its limitations. I carefully hedged each bullet with "easily", because PDF does make it possible to overcome each limitation, at least partially. PDFs can be annotated with their logical structure to create a tagged PDF. Most PDF exporters will not add tags automatically — the simplest option is to use Adobe's subscription-only Acrobat Pro, which provides an "Automatically tag PDF" action. For example, here is a recent paper of mine with added tags:
  100. A LaTeX-generated paper with automatically added tags.</p>
  101. <p>If you squint, you can see that the logical structure closely resembles the HTML document model. The document has sections, headings, paragraphs, and links. Adobe characterizes the logical structure as an accessibility feature, but it has other benefits. You may be surprised to know that Adobe Acrobat allows you to reflow tagged PDFs at different screen sizes. You may be unsurprised to know that reflowing does not always work well. For example:
  102. A section of the paper in its default fixed layout. Note that the second paragraph is wrapped around the code snippet.
  103. The same section of the paper after reflowing to a smaller width. Note that the code is now interleaved with the second paragraph.</p>
  104. <p>In theory, these issues could be fixed. If the world's PDF exporters could be modified to include logical structure. If Adobe's reflowing algorithm could be improved to fix its edge cases. If the reflowing algorithm could be specified, and if Adobe were willing to release it publicly, and if it were implemented in each PDF viewer. And that doesn't even cover interaction! So in practice, I don't think we can just fix the PDF format, at least within a reasonable time frame.</p>
  105. <h2>The Good and Bad of HTML</h2>
  106. <p>In the meantime, we already have a structured document format which can be flexibly and interactively rendered: HTML (and CSS and Javascript, but here just collectively referred to as HTML). The HTML format provides almost exactly the inverse advantages and disadvantages of PDF.</p>
  107. <ul>
  108. <li>HTML can more easily adapt to different screen sizes. Over the last 20 years, web developers and browser vendors have created a wide array of techniques for responsive design.</li>
  109. <li>HTML can be more easily understood by a program. HTML provides both an inherent structure plus additional attributes to support accessibility tools.</li>
  110. <li>HTML can more easily express interaction. People have used HTML to produce amazing interactive documents that would be impossible in PDF. Think: Distill.pub, Explorable Explanations, Bartosz Ciechanowski, and Bret Victor, just to name a few.</li>
  111. </ul>
  112. <p>Again, these advantages are hedged with "more easily". One can easily produce a convoluted or inaccessible HTML document. But on balance, these aspects are more true than not compared to PDF. However, HTML is lacking where PDF shines:</p>
  113. <ul>
  114. <li>HTML is not self-contained. HTML files may contain URL references to external files that may be hosted on a server. One can rarely download an HTML file and have it render correctly without an internet connection.</li>
  115. <li>HTML is not always rendered consistently. HTML's dynamic layout means that an author may not see the same document as a reader. Moreover, HTML layout is not fully specified, so browsers may differ in their implementation.</li>
  116. <li>HTML is not fully stable over time. Browsers try to maintain backwards compatibility (come on and slam!), but the HTML format is still evolving. The HTML standard is a "living standard" due to the rapidly changing needs and feature sets of modern browsers.</li>
  117. </ul>
  118. <p>So I've been thinking: how can we design HTML documents to gain the benefits of PDFs without losing the key strengths of HTML? The rest of this document will present some early prototypes and tentative proposals in this direction.</p>
  119. <h2>Self-Contained HTML with EPUB</h2>
  120. <p>First, how can we make HTML documents self-contained? This is an old problem with many potential solutions. WARC, webarchive, and MHTML are all file formats designed to contain all the resources needed to render a web page. But these formats are more designed for snapshotting an existing website, rather than serving as a single source of truth for a web document. From my research, the most sensible format for this purpose is EPUB.</p>
  121. <p>EPUB is a "distribution and interchange format for digital publications and documents", per the EPUB 3 Overview. Reductively, an EPUB is a ZIP archive of web files: HTML, CSS, JS, and assets like images and fonts. On a technical level, what distinguishes EPUB from archival formats is that EPUB includes well-specified files that describe metadata about a document. On a social level, EPUB appears to be the HTML publication format with the most adoption and momentum in 2024, compared to moribund formats like Mobi.</p>
  122. <p>The EPUB spec has all the gory details, but to give you a rough sense, a sample EPUB might have the following file structure:</p>
  123. <pre><code>sample.epub
  124. ├── META-INF
  125. │ └── container.xml
  126. └── EPUB
  127. ├── package.opf
  128. ├── nav.xhtml
  129. ├── chapter1.xhtml
  130. ├── chapter2.xhtml
  131. └── img
  132. └── sample.jpg
  133. </code></pre>
  134. <p>An EPUB contains content documents (like chapter1.xhtml and chapter2.xhtml) which contain the core HTML content. Content documents can contain relative links to assets in the EPUB, like img/sample.jpg. The navigation document (nav.xhtml) provides a table of contents, and the package document (package.opf) provides metadata about the document. These files collectively define one "rendition" of the whole document, and the container file (container.xml) points to each rendition contained in the EPUB.</p>
  135. <p>The EPUB format optimizes for machine-readable content and metadata. HTML content is required to be in XML format (hence, XHTML). Document metadata like the title and author is provided in structured form in the package document. The navigation document has a carefully prescribed tag structure so the TOC can be consistently extracted.</p>
  136. <p>Overall, EPUB's structured format makes it a solid candidate for a single-file HTML document container. However, EPUB is not a silver bullet. EPUB is quite permissive in what kinds of content can be put into a content document.</p>
  137. <p>For example, a major issue for self-containment is that EPUB content can embed external assets. A content document can legally include an image or font file whose src is a URL to a hosted server. This is not hypothetical, either; as of the time of writing, Google Doc's EPUB exporter will emit CSS that will @include external Google Fonts files. The problem is that such an EPUB will not render correctly without an internet connection, nor will it render correctly if Google changes the URLs of its font files.</p>
  138. <p>Hence, I will propose a new format which I call a portable EPUB, which is an EPUB with additional requirements and recommendations to improve PDF-like portability. The first requirement is:
  139. Local asset requirement: All assets (like images, scripts, and fonts) embedded in a content document of a portable EPUB must refer to local files included in the EPUB. Hyperlinks to external files are permissible.</p>
  140. <h2>Consistency vs. Flexibility in Rendering</h2>
  141. <p>There is a fundamental tension between consistency and flexibility in document rendering. A PDF is consistent because it is designed to render in one way: one layout, one choice of fonts, one choice of colors, one pagination, and so on. Consistency is desirable because an author can be confident that their document will look good for a reader (or at least, not look bad). Consistency has subtler benefits — because a PDF is chunked into a consistent set of pages, a passage can be cited by referring to the page containing the passage.</p>
  142. <p>On the other hand, flexibility is desirable because people want to read documents under different conditions. Device conditions include screen size (from phone to monitor) and screen capabilities (E-ink vs. LCD). Some readers may prefer larger fonts or higher contrasts for visibility, alternative color schemes for color blindness, or alternative font faces for dyslexia. Sufficiently flexible documents can even permit readers to select a level of detail appropriate for their background (here's an example).</p>
  143. <p>Finding a balance between consistency and flexibility is arguably the most fundamental design challenge in attempting to replace PDF with EPUB. To navigate this trade-off, we first need to talk about EPUB reading systems, or the tools that render an EPUB for human consumption. To get a sense of variation between reading systems, I tried rendering this post as an EPUB (without any styling, just HTML) on four systems: Calibre, Adobe Digital Editions, Apple Books, and Amazon Kindle. This is how the first page looks on each system (omitting Calibre because it looked the same as Adobe Digital Editions):</p>
  144. <ul>
  145. <li>Adobe Digital Editions</li>
  146. <li>Apple Books</li>
  147. <li>Amazon Kindle</li>
  148. </ul>
  149. <p>Calibre and Adobe Digital Editions both render the document in a plain web view, as if you opened the HTML file directly in the browser. Apple Books applies some styling, using the New York font by default and changing link decorations. Amazon Kindle increases the line height and also uses my Kindle's globally-configured default font, Palatino.</p>
  150. <p>As you can see, an EPUB may look quite different on different reading systems. The variation displayed above seems reasonable to me. But how different is too different? For instance, I was recently reading A History of Writing on my Kindle. Here's an example of how a figure in the book renders on the Kindle:
  151. A figure in the EPUB version of A History of Writing on my Kindle</p>
  152. <p>When I read this page, I thought, "wow, this looks like crap." The figure is way too small (although you can long-press the image and zoom), and the position of the figure seems nonsensical. I found a PDF version online, and indeed the PDF's figure has a proper size in the right location:
  153. A figure in the PDF version of A History of Writing on my Mac</p>
  154. <p>This is not a fully fair comparison, but it nonetheless exemplifies an author's reasonable concern today with EPUB: what if it makes my document looks like crap?</p>
  155. <h2>Principles for Consistent EPUB Rendering</h2>
  156. <p>I think the core solution for consistently rendering EPUBs comes down to this:</p>
  157. <ul>
  158. <li>The document format (i.e., portable EPUB) needs to establish a subset of HTML (call it "portable HTML") which could represent most, but not all, documents.</li>
  159. <li>Reading systems need to guarantee that a document within the subset will always look reasonable under all reading conditions.</li>
  160. <li>If a document uses features outside this subset, then the document author is responsible for ensuring the readability of the document.</li>
  161. </ul>
  162. <p>If someone wants to write a document such as this post, then that person need not be a frontend web developer to feel confident that their document will render reasonably. Conversely, if someone wants to stuff the entire Facebook interface into an EPUB, then fine, but it's on them to ensure the document is responsive.</p>
  163. <p>For instance, one simple version of portable HTML could be described by this grammar:</p>
  164. <pre><code>Document ::= &lt;article&gt; Block* &lt;/article&gt;
  165. Block ::= &lt;p&gt; Inline* &lt;/p&gt; | &lt;figure&gt; Block* &lt;/figure&gt;
  166. Inline ::= text | &lt;strong&gt; Inline* &lt;/strong&gt;
  167. </code></pre>
  168. <p>The EPUB spec already defines a comparable subset for navigation documents. I am essentially proposing to extend this idea for content documents, but as a soft constraint rather than a hard constraint. Finding the right subset of HTML will take some experimentation, so I can only gesture toward the broad solution here.
  169. Portable HTML rendering requirement: if a document only uses features in the portable HTML subset, then a portable EPUB reading system must guarantee that the document will render reasonably.
  170. Portable HTML generation principle: when possible, systems that generate portable EPUBs should output portable HTML.</p>
  171. <p>A related challenge is to define when a particular rendering is "good" or "reasonable", so one could evaluate either a document or a reading system on its conformance to spec. For instance, if document content is accidentally rendered in an inaccesible location off-screen, then that would be a bad rendering. A more aggressive definition might say that any rendering which violates accessibility guidelines is a bad rendering. Again, finding the right standard for rendering quality will take some experimentation.</p>
  172. <p>If an author is particularly concerned about providing a single "canonical" rendering of their document, one fallback option is to provide a fixed-layout rendition. The EPUB format permits a rendition to specify that it should be rendered in fixed viewport size and optionally a fixed pagination. A fixed-layout rendition could then manually position all content on the page, similar to a PDF. Of course, this loses the flexibility of a reflowable rendition. But an EPUB could in theory provide multiple renditions, offering users the choice of whichever best suits their reading conditions and aesthetic preferences.
  173. Fixed-layout fallback principle: systems that generate portable EPUBs can consider providing both a reflowable and fixed-layout rendition of a document.</p>
  174. <p>It's possible that the reading system, the document author, and the reader can each express preferences about how a document should render. If these preferences are conflicting, then the renderer should generally prioritize the reader over the author, and the author over the reading system. This is an ideal use case for the "cascading" aspect of CSS:
  175. Cascading styles principle: both documents and reading systems should express stylistic preferences (such as font face, font size, and document width) as CSS styles which can be overriden (e.g., do not use !important). The reading system should load the CSS rules such that the priority order is reading system styles &lt; document styles &lt; reader styles.</p>
  176. <h2>A Lighter EPUB Reading System</h2>
  177. <p>The act of working with PDFs is relatively fluid. I can download a PDF, quickly open it in a PDF reading system like Preview, and keep or discard the PDF as needed. But EPUB reading systems feel comparatively clunky. Loading an EPUB into Apple Books or Calibre will import the EPUB into the application's library, which both copies and potentially decompresses the file. Loading an EPUB on a Kindle requires waiting several minutes for the Send to Kindle service to complete.</p>
  178. <p>Worse, EPUB reading systems often don't give you appropriate control over rendering an EPUB. For example, to emulate the experience of reading a book, most reading systems will chunk an EPUB into pages. A reader cannot scroll the document but rather "turn" the page, meaning textually-adjacent content can be split up between pages. Whether a document is paginated or scrolled should be a reader's choice, but 3/4 reading systems I tested would only permit pagination (Calibre being the exception).</p>
  179. <p>Therefore I decided to build a lighter EPUB reading system, Bene. You're using it right now. This document is an EPUB — you can download it by clicking the button in the top-right corner. The styling and icons are mostly borrowed from pdf.js. Bene is implemented in Tauri, so it can work as both a desktop app and a browser app. Please appreciate this picture of Bene running as a desktop app:
  180. The Bene reading system running as a desktop app. Wow! It works!</p>
  181. <p>Bene is designed to make opening and reading an EPUB feel fast and non-committal. The app is much quicker to open on my Macbook (&lt;1sec) than other desktop apps. It decompresses files on-the-fly so no additional disk space is used. The backend is implemented in Rust and compiled to Wasm for the browser version.</p>
  182. <p>The general design goal of Bene is to embody my ideals for a portable EPUB reader. That is, a utilitarian interface into an EPUB that satisfies my additional requirements for portability. Bene allows you to configure document rendering by changing the font size (try the +/- buttons in the top bar) and the viewer width (if you're on desktop, move your mouse over the right edge of the document, and drag the handle). Long-term, I want Bene to also provide richer document interactions than a standard EPUB reader, which means we must discuss scripting.</p>
  183. <h2>Defensively Scripting EPUBs</h2>
  184. <p>To some people, the idea of code in their documents is unappealing. Last time one of my document-related projects was posted to Hacker News, the top comment was complaining about dynamic documents. The sentiment is understandable — concerns include:</p>
  185. <ul>
  186. <li>Bad code: your document shouldn't crash or glitch due to a failure in a script.</li>
  187. <li>Bad browsers: your document shouldn't fail to render when a browser updates.</li>
  188. <li>Bad actors: a malicious document shouldn't be able to pwn your computer.</li>
  189. <li>Bad interfaces: a script shouldn't cause your document to become unreadable.</li>
  190. </ul>
  191. <p>Yet, document scripting provides many opportunities for improving how we communicate information. For one example, if you haven't yet, try hovering your mouse over any instance of the term portable EPUB (or long press it on a touch screen). You should see a tooltip appear with the term's definition. The goal of these tooltips is to simplify reading a document that contains a lot of specialized notation or terminology. If you forget a definition, you can quickly look it up without having to jump around.</p>
  192. <p>The key design challenge is how to permit useful scripting behaviors while limiting the downsides of scripting. One strategy is as follows:
  193. Structure over scripts principle: documents should prefer structural annotations over scripts where possible. Documents should rely on reading systems to utilize structure where possible.</p>
  194. <p>As an example of this principle, consider how the portable EPUB definition and references are expressed in this document:
  195. Creating a definition
  196. Referencing a definition</p>
  197. <p>The definition uses the <code>&lt;dfn&gt;</code> element wrapped in a custom <code>&lt;dfn-container&gt;</code> element to indicate the scope of the definition. The reference to the definition uses a standard anchor with an addition data-target attribute to emphasize that a definition is being linked. The document itself does not provide a script. The Bene reading system automatically detects these annotations and provides the tooltip interaction.</p>
  198. <h2>Encapsulating Scripts with Web Components</h2>
  199. <p>But what if a document wants to provide an interactive component that isn't natively supported by the reading system? For instance, I have recently been working with The Rust Programming Language, a textbook that explains the different features of Rust. It contains a lot of passages like this one:</p>
  200. <p>This program first binds x to a value of 5. Then it creates a new variable x by repeating let x =, taking the original value and adding 1 so the value of x is then 6. Then, within an inner scope created with the curly brackets, the third let statement also shadows x and creates a new variable, multiplying the previous value by 2 to give x a value of 12. When that scope is over, the inner shadowing ends and x returns to being 6. When we run this program, it will output the following:</p>
  201. <p>A challenge in reading this passage is finding the correspondences between the prose and the code. An interactive code reading component can help you track those correspondences, like this (try mousing-over or clicking-on each sentence):</p>
  202. <p>The interactive code description component is used as follows:</p>
  203. <p>Again, the document content contains no actual script. It contains a custom element <code>&lt;code-description&gt;</code>, and it contains a series of annotations as spans and anchors. The <code>&lt;code-description&gt;</code> element is implemented as a web component.</p>
  204. <p>Web components are a programming model for writing encapsulated interactive fragments of HTML, CSS, and Javascript. Web components are one of many ways to write componentized HTML, such as React, Solid, Svelte, and Angular. I see web components as the most suitable as a framework for portable EPUBs because:</p>
  205. <ul>
  206. <li>Web components are a standardized technology. Its key features like custom elements (for specifying the behavior of novel elements) and shadow trees (for encapsulating a custom element from the rest of the document) are part of the official HTML and DOM specifications. This improves the likelihood that future browsers will maintain backwards compatibility with web components written today.</li>
  207. <li>Web components are designed for tight encapusulation. The shadow tree mechanism ensures that styling applied within a custom component cannot accidentally affect other components on the page.</li>
  208. <li>Web components have a decent ecosystem to leverage. As far as I can tell, web components are primarily used by Google, which has created notable frameworks like Lit.</li>
  209. <li>Web components provide a clear fallback mechanism. If a renderer does not support Javascript, or if a renderer loses the ability to render web components, then an HTML renderer will simply ignore custom tags and render their contents.</li>
  210. </ul>
  211. <p>Thus, I propose one principle and one requirement:
  212. Encapsulated scripts principle: interactive components should be implemented as web components when possible, or otherwise be carefully designed to avoid conflicting with the base document or other components.
  213. Components fallback requirement: interactive components must provide a fallback mechanism for rendering a reasonable substitute if Javascript is disabled.</p>
  214. <h2>Where To Go From Here?</h2>
  215. <p>Every time I have told someone "I want to replace PDF", the statement has been met with extreme skepticism. Hopefully this document has convinced you that HTML-via-EPUB could potentially be a viable and desirable document format for the future.</p>
  216. <p>My short-term goal is to implement a few more documents in the portable EPUB format, such as my PLDI paper. That will challenge both the file format and the reading system to be flexible enough to support each document type. In particular, each document should look good under a range of reading conditions (screen sizes, font sizes and faces, etc.).</p>
  217. <p>My long-term goal is to design a document language that makes it easy to generate portable EPUBs. Writing XHTML by hand is not reasonable. I designed Nota before I was thinking about EPUBs, so its next iteration will be targeted at this new format.</p>
  218. <p>If you have any thoughts about how to make this work or why I'm wrong, let me know by email or Twitter or Mastodon or wherever this gets posted. If you would like to help out, please reach out! This is just a passion project in my free time (for now...), so any programming or document authoring assistance could provide a lot of momentum to the project.</p>
  219. <h2>But What About...</h2>
  220. <p>A brief postscript for a few things I haven't touched on.</p>
  221. <p>...security? You might dislike the idea that document authors can run arbitrary Javascript on your personal computer. But then again, you presumably use both a PDF reader and a web browser on the daily, and those both run Javascript. What I'm proposing is not really any less secure than our current state of affairs. If anything, I'd hope that browsers are more battle-hardened than PDF viewers regarding code execution. Certainly the designers of EPUB reading systems should be careful to not give documents any additional capabilities beyond those already provided by the browser.</p>
  222. <p>...aesthetics? People often intuit that LaTeX-generated PDFs look prettier than HTML documents, or even prettier than PDFs created by other software. This is because Donald Knuth took his job very seriously. In particular, the Knuth-Plass line-breaking algorithm tends to produce better-looking justified text than whatever algorithm is used by browsers.</p>
  223. <p>There's two ways to make progress here. One is for browsers to provide more typography tools. Allegedly, text-wrap: pretty is supposed to help, but in my brief testing it doesn't seem to improve line-break quality. The other way is to pre-calculate line breaks, which would only work for fixed-layout renditions.</p>
  224. <p>...page citations? I think we just have to give up on citing content by pages. Instead, we should mandate a consistent numbering scheme for block elements within a document, and have people cite using that scheme. For example, Bene will auto-number all blocks. If you're on a desktop, try hovering your mouse in the left column next to the top-right of any paragraph.</p>
  225. </article>
  226. <hr>
  227. <footer>
  228. <p>
  229. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  230. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  231. </svg> Accueil</a> •
  232. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  233. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  234. </svg> Suivre</a> •
  235. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  236. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  237. </svg> Pro</a> •
  238. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  239. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  240. </svg> Email</a> •
  241. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  242. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  243. </svg> Légal</abbr>
  244. </p>
  245. <template id="theme-selector">
  246. <form>
  247. <fieldset>
  248. <legend><svg class="icon icon-brightness-contrast">
  249. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  250. </svg> Thème</legend>
  251. <label>
  252. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  253. </label>
  254. <label>
  255. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  256. </label>
  257. <label>
  258. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  259. </label>
  260. </fieldset>
  261. </form>
  262. </template>
  263. </footer>
  264. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  265. <script>
  266. function loadThemeForm(templateName) {
  267. const themeSelectorTemplate = document.querySelector(templateName)
  268. const form = themeSelectorTemplate.content.firstElementChild
  269. themeSelectorTemplate.replaceWith(form)
  270. form.addEventListener('change', (e) => {
  271. const chosenColorScheme = e.target.value
  272. localStorage.setItem('theme', chosenColorScheme)
  273. toggleTheme(chosenColorScheme)
  274. })
  275. const selectedTheme = localStorage.getItem('theme')
  276. if (selectedTheme && selectedTheme !== 'undefined') {
  277. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  278. }
  279. }
  280. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  281. window.addEventListener('load', () => {
  282. let hasDarkRules = false
  283. for (const styleSheet of Array.from(document.styleSheets)) {
  284. let mediaRules = []
  285. for (const cssRule of styleSheet.cssRules) {
  286. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  287. continue
  288. }
  289. // WARNING: Safari does not have/supports `conditionText`.
  290. if (cssRule.conditionText) {
  291. if (cssRule.conditionText !== prefersColorSchemeDark) {
  292. continue
  293. }
  294. } else {
  295. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  296. continue
  297. }
  298. }
  299. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  300. }
  301. // WARNING: do not try to insert a Rule to a styleSheet you are
  302. // currently iterating on, otherwise the browser will be stuck
  303. // in a infinite loop…
  304. for (const mediaRule of mediaRules) {
  305. styleSheet.insertRule(mediaRule.cssText)
  306. hasDarkRules = true
  307. }
  308. }
  309. if (hasDarkRules) {
  310. loadThemeForm('#theme-selector')
  311. }
  312. })
  313. </script>
  314. </body>
  315. </html>