News from paged.js! the latest news from paged.js and web2print development 2025-11-07T00:00:00Z https://pagedjs.org/ @julientaq Successfully published @pagedjs/paged-page 2025-11-07T00:00:00Z https://pagedjs.org/posts/en/successfully-published-@pagedjspaged-page/ <blockquote> <p>Well, you know November has come<br> When it's gone away</p> </blockquote> <ul> <li>Gorillaz, <em>November has come</em></li> </ul> <p>Sorry for the silence, november came and with it, all the slowness of winter, which, this year, got the form of a quite strong covid. The good thing is that it’s now away, and i’m back up and running, and it’s the perfect moment to announce one of the great wins for paged.js rebuilding session we’re hard working for.</p> <h2 id="the-benefits-of-a-cssprint-preview" tabindex="-1">The benefits of a cssPrint preview</h2> <p>As far as i remember, i always used the browser to generate books using CSSPrint. I never got the hard experience of generating a PDF through the command line, to check the result and tweak the content, to do it again, and again.<br> I got the luxury of getting into cssPrint using book.js, a project founded by Adam Hyde (like paged.js) that was using CSS Regions to generate page. You made a change on page 2, and all the book was rebuilding from there. And we could quickly try things using the inspector and everything was visible on screen. But CSS Regions were drop by the Chromium team and what was amazing just disappeared. So we didn’t update Chrome for quite a while. And WebKit followed, and everything about CSS regions disappeared.</p> <p>I ended up using a very precise Chromium under a very special Ubuntu version under a virtual machine for a long time (and we didn’t have SSD then, everything was so long). And i wasn’t the only one strugglin, even the folks at Open Source Publishing ended up making <a href="https://pagedjs.org/posts/en/successfully-published-@pagedjspaged-page/blog.osp.kitchen/residency/from-webkit-to-ospkit.html">their own fork on webkit to support their design work</a>. We, designers, love to experiment with our tools, and the browser is one of the most accessible setup for that. We need to make a poster? We’re gonna build our own system for previewing on screen what our HTML and CSS will render. And to do so, we spend quite a long time to figure out the HTML and CSS that will allows us to see what we’re gonna print.</p> <p>But most of the time, this html and this css is litterally a simplest version of what paged.js generate to look at it on a screen. We have a <code>&lt;div&gt;</code> that will be the page, and that will have a CSS to handle the preview of the screen: setting the size of the <code>&lt;div&gt;</code> to be equal to what you’ll set in the <code>@page</code>, make sure to set the overflow accordingly, and, if you really want to reuse the system, you’re setting up a precise CSS grid, with margins, space for running head, etc.</p> <p>And by the game of copy/pasting, we’re rebuilding the same thing every time we need, and it’s not fun, because we always forget a line, or get into a new bug, because copy and pasting is far from free of errors.</p> <p>That’s why, when we decided to update paged.js, we decided that any bit of the library that could be reused outside will be made available as such. Today, we’re releasing the first block of this, the <code>&lt;paged-page&gt;</code> component.</p> <h2 id="but-hey%2C-what-is-a-web-component%3F" tabindex="-1">But hey, what is a web-component?</h2> <p>HTML is made of standard tags that we all share from one web page to another. <code>&lt;h1&gt;</code> is a level one title, <code>&lt;p&gt;</code> is a paragraph and <code>&lt;figure&gt;</code> an element that will be understood by readers and computers, as a <code>figure</code>. Those tags come with attributes (like <code>id</code> or <code>class</code> for the most well known ones), and a behavior that has been defined by the W3C, and implemented in a similar way in all the browsers. A good example? an <code>&lt;img&gt;</code> tag has a <code>alt</code> attribute. This attribute give an opportunity to the author to add a description of the image that will be picked up by a screen reader and read aloud to, for example, a person with visibility issues. This behavior is described in the specs, and give some rules on how an element will work.</p> <p>A web-component is a set of techonologies allowing author to write their own component.</p> <p>Using javascript, a web-component will include the HTML structure (the template), the CSS (the default styles), and their own behavior (how the element will react to a user). And to use it, you’ll only need the javascript file that define all those, and then you can simply add the component where you need in your webpage.</p> <p>One of my favorite web-component is a preview of a keybaord called <a href="https://onedeadkey.github.io/x-keyboard/">x-keyboard</a> (and its <a href="https://github.com/OneDeadKey/x-keyboard">source</a>). It’s the perfect tool to show a keybaord layout on the screen, and it will even be able to pick up what the visitor will type to and react accordingly.</p> <p>So <code>paged-page</code> is a web-component to show the preview of a printed page on the screen, following the W3C instructions used for printing.</p> <p>You want to print a page with a huge text in the middle of your page?</p> <p>This is the HTML you’ll write:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-page</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>The store will be closed for Christmas. See you in January!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-page</span><span class="token punctuation">></span></span></code></pre> <p>All the CSS for the preview, and for the print, comes with the component. This is already a win.</p> <p>And we’ve been a bit further, and added attributes to handle all the needed CSS directly from the HTML element: bleed, marks, margin, width and height are added as attributes and transfered to the CSS and the HTML.</p> <p>A good thing with a web-component, is that it can be transformed with CSS quite easily: you only need to do what you would do with a classic HTML tag, like this:</p> <pre class="language-css"><code class="language-css"><span class="token selector">paged-page#id</span> <span class="token punctuation">{</span><br> <span class="token property">padding</span><span class="token punctuation">:</span> 3em<span class="token punctuation">;</span><br> <span class="token property">background</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>…and you’re done, your page has now a padding of 3mm and a green background.</p> <p>Pretty easy, right? I hope you’re gonna enjoy this, we’re really excited with the possibility this will offer.</p> <h2 id="cascading-pages-or-how-i-learned-to-style-the-content-inside-the-page" tabindex="-1">Cascading pages or how I learned to style the content inside the page</h2> <p>Conceptually, in the word of web to print, the sheet of paper doesn’t impact the layout of its content (outside of what the @page can do): in short, you can’t define how the content of the page look depending on the type of page it’s on.</p> <p>A simple example: let say that your design needs to have the text on the thirteenth page in another color and you don’t know before hand what would be on this page, you would asssume that you could use the following code:css</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span><span class="token punctuation">:</span><span class="token function">nth</span><span class="token punctuation">(</span>13<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br> <span class="token selector">.funny-text</span> <span class="token punctuation">{</span><br> <span class="token property">color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>Well, you can’t. Because the specs does not allow anything not page related on the <code>@page</code>. You can have margins, bleeds, marks and set the geometry of the page with the size property, but that’s it.</p> <p>Because this would create a cascade issue: what if somewhere else in your CSS, you write this</p> <pre class="language-css"><code class="language-css"><span class="token selector">.funny-text</span> <span class="token punctuation">{</span><span class="token property">color</span><span class="token punctuation">:</span>yellow<span class="token punctuation">}</span>`</code></pre> <p>What color would be your text?</p> <p>And then, think of all the weird thing you could do with text-size: if the text needs to be huge on page 10, but making it huge push it to page 11, what should you have on the page 10 then?</p> <p>Well, paged.js has a weird answer to that issue, because of the transformation it makes on the css stylesheet. You see, any <code>@page:nth(13)</code> selector is transformed into a class: <code>@page</code> become <code>div.paged_page.paged_nth_13</code> which totally accepts nested CSS, and therefore, will have no trouble with styles for the children of that page, and the specificity rules will be quite clear.</p> <p>I’m calling this the quantum cascade: it is and it is not, until it’s appearing on the page you’ll print in the end.</p> <p>But it’s a bit of a lucky game, because sometimes, you don’t want that to happen, and your stuck with this <em>not-a-bug-a-feature</em> that paged.js offers. Thankfully, in the world of web component, it’s a bit different. Picture this HTML</p> <pre class="language-html"><code class="language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-page</span><br> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-12<span class="token punctuation">"</span></span><br> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id-of-the-page2<span class="token punctuation">"</span></span><br> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">bleed</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">margin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>8mm 14mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">marks</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>cross crop<span class="token punctuation">"</span></span><br> <span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>This is a regularly sized page.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span> there will be some content here.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-page</span><span class="token punctuation">></span></span><br></code></pre> <p>If I want to change the color of the text, and add this CSS:</p> <pre class="language-css"><code class="language-css"> <span class="token selector">#page-12</span> <span class="token punctuation">{</span><br> <span class="token property">background</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span><br> <span class="token selector">h2</span> <span class="token punctuation">{</span><br> <span class="token property">color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span></code></pre> <p>As you can see the component is almost invisible, and you can easily change the content following the classic cascade.</p> <p>But maybe i want to change the style of the page-area, then we need to make the component visible. That’s what the <code>::part</code> pseudo elements is for.</p> <pre class="language-css"><code class="language-css"><span class="token selector">#page-12::part(page-area)</span> <span class="token punctuation">{</span><br> <span class="token property">background</span><span class="token punctuation">:</span> yellow<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>This could seem not that useful, because right now, we’re only talking about <code>paged-area</code>, but as soon as you get margins in, it becomes extremely powerful because you can target very deep css with a simple shortcut:</p> <pre class="language-css"><code class="language-css"><span class="token selector">#page-12:part(bottom-center)</span> <span class="token punctuation">{</span> <span class="token property">text-transformation</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span> <span class="token property">font-size</span><span class="token punctuation">:</span> .8em<span class="token punctuation">}</span><br><span class="token selector">#page-12:part(bottom-right)::after</span> <span class="token punctuation">{</span><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">counter</span><span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">}</span></code></pre> <h2 id="a-recap" tabindex="-1">A recap</h2> <p><code>&lt;paged-page&gt;</code> is a component that is waiting for those attributes:</p> <ul> <li><code>width</code>: the width of the page (without bleed)</li> <li><code>height</code>: the height of the page (without bleed)</li> <li><code>bleed</code>: the amount of bleed. (right now, you can’t have custom bleeds per side, but we’re thinking about it)</li> <li><code>margin</code>: the margins of the page, written down exactly as their css counterpart.</li> <li><code>marks</code>: the crop marks and cross marks you can add to the page</li> </ul> <p>And since it’s HTML, you can add any property you’d need for your own code. For example, paged.js will add <code>data-paged-ref</code> to support the page break system.</p> <p>The component itself is made of three elements:</p> <ul> <li>the page-marks: for bleed and marks.</li> <li>the paged-margins: allowing for quick access to margin-boxes using the <code>paged-margins</code> webcomponent.</li> <li>the page-area: where the content of the component will appear.</li> </ul> <p>If you happen to have multiple page with multiple page size, save as PDF will create a PDF with different page size.</p> <h2 id="about-margins" tabindex="-1">About margins</h2> <p>Since we were quite happy with the paged-margins, we got into exploring margin-boxes as web-components. As you may know, in the land of CSSPrint, the page has a limited of places where you can add things in the margins. THe specifications say that there are 17 margin-boxes, following this diagram:</p> <figure> <img src="https://pagedjs.org/images/margin-boxes.png"></figure> <p>As you can see, the place you can add content is quite limited, and the geometry will be dependant on what you’ll have in there. It’s one of the thing we never make when we do HTML+CSS for printing, without using pagedjs or other things. We just don’t bother adding them, and we end up adding some content with a position absolute on each page, because more is too much.</p> <p>But if the preview of your page can have those margins, you may consider using them, and if they are needed for paged.js we added them, and it’s pretty easy to bring them up:</p> <pre class="language-html"><code class="language-html"><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-page</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margins</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-margins<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margin-content</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>top-left<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Does this appear?<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margin-content</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margin-content</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>top-right<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Should have<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margin-content</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margin-content</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>left-top<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>T<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margin-content</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margins</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>there are margin everywhere !<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-page</span><span class="token punctuation">></span></span></code></pre> <p>In that HTML, we have a page, that contains the margins, and the rest of the content will fill up the page-area.</p> <p>We hope you gonna love playing with it, we’re already pretty much excited to put that into paged.js!</p> <blockquote> <p>wanna test it quickly? Include that script to your HTML and start making things!</p> </blockquote> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><br> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>module<span class="token punctuation">"</span></span><br> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/@pagedjs/[email protected]/dist/PagedPreview.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre> <hr> <p>On a side note, we got an issue for some translation of the documentation, and spanish may be the next language for paged.js documentation!</p> <p><em>¡Vale!</em></p> <paged-page> la preview des pages, avec ou sans paged.js 2025-11-07T00:00:00Z https://pagedjs.org/posts/fr/lesspaged-pagegreater-la-preview-des-pages-avec-ou-sans-paged.js/ <blockquote> <p>Well, you know November has come<br> When it's gone away</p> </blockquote> <ul> <li>Gorillaz, <em>November has come</em></li> </ul> <p>Bonjour tout le monde, j’espère que vous allez bien.</p> <p>Pardon pour le silence, novembre est là et avec lui la lenteur de l’hiver, qui, cette année, a pris la forme d’un covid assez costaud. La bonne nouvelle, c’est que j’en ai fini avec lui pour cette année, on reprend le travail et c’est le moment parfait pour annoncer une chouette avancée dans notre travail de reconstruction de paged.js. Mais avant de plonger dedans, un petit peu de pourquoi.</p> <h2 id="les-b%C3%A9n%C3%A9fices-d%E2%80%99une-pr%C3%A9visualisation-cssprint" tabindex="-1">Les bénéfices d’une prévisualisation cssPrint</h2> <p>Je suis un chanceux, par ce que j’ai toujours utilisé le navigateur pour générer des livres avec CSSPrint. Je n’ai jamais connu l’expérience laborieuse de générer un PDF en ligne de commande, de vérifier le résultat, de retoucher pour régénérer, encore et encore.</p> <p>J’ai eu le luxe d’aborder cssPrint via <code>book.js</code>, un projet fondé par Adam Hyde (comme paged.js) qui utilisait les CSS Regions pour générer les pages. Vous faisiez un changement à la page 2, et tout le livre se reconstruisait à partir de là. Et on pouvait tester rapidement toute nouvelle idée improbable grâce à l’inspecteur, tout était visible à l’écran. Mais les CSS Regions ont été abandonnées par l’équipe de Chromium, puis WebKit a suivi, et tout ce qui concernait les CSS Regions a disparu.</p> <p>J’ai dû utiliser une version très précise de Chromium, qui tournait sous une version très particulière d’Ubuntu dans une machine virtuelle sur un mac en galère pendant (trop) longtemps (et à l’époque, nous n’avions pas de SSD, tout était tellement lent).</p> <p>Et j’étais pas le seul à galérer : même l’équipe d’Open Source Publishing a fini par créer leur propre fork de WebKit pour soutenir leur travail de design graphique.</p> <p>Nous, designers, aimons expérimenter avec nos outils, et le navigateur est l’un des environnements les plus accessibles pour ça. Besoin de faire une affiche ? On va construire notre propre système de prévisualisation à l’écran pour s’assurer que le print corresponde à ce qu’on a en tête. Et pour y parvenir, on passe beaucoup de temps à reproduire une page à l’écran (et prête à être imprimée).</p> <p>Mais la plupart du temps, cet HTML et ce CSS sont littéralement une version simplifiée de ce que paged.js génère pour l’affichage à l’écran: on crée un <code>&lt;div&gt;</code> qui représente la page, avec du CSS pour gérer la prévisualisation : on donne à ce <code>&lt;div&gt;</code> la taille définie dans le @page, on règle l’<em>overflow</em>, et si on veut vraiment réutiliser le système, on définit une grille CSS précise (mais qu’on ne réutilise jamais vraiment).</p> <p>Et à force de copier/coller, on reconstruit la même chose à chaque fois qu’on en a besoin, et c’est pas très marrant, parce qu’on oublie toujours une ligne ou on tombe sur un nouveau bug et on passe du temps à gérer des galères d’oubli là ou on devrait apprécier un moment de design.</p> <p>Quand on a décidé de mettre à jour paged.js, il était évident que chaque morceau du programme pouvant être réutilisé à l’extérieur serait rendu disponible tel quel. Aujourd’hui, nous publions le premier bloc : le composant web <paged-page>.</paged-page></p> <h2 id="mais-au-fait%2C-c%E2%80%99est-quoi-un-web-component-%3F" tabindex="-1">Mais au fait, c’est quoi un web-component ?</h2> <p>HTML est fait de balises standards que l’on partage tous d’une page web à l’autre, comme un langage commun. <code>&lt;h1&gt;</code> est un titre de niveau 1, <code>&lt;p&gt;</code> un paragraphe, et <code>&lt;figure&gt;</code> un élément qui sera compris par les lecteurs d’écran comme une figure. Ces balises ont des attributs (par exemple <code>id</code> ou <code>class</code>, les plus connus) et un comportement défini par le W3C et implémenté de façon similaire dans les navigateurs. Par exemple : une balise <code>&lt;img&gt;</code> possède un attribut <code>alt</code>. Cet attribut permet à l’auteur de fournir une description de l’image, qui sera lue par un lecteur d’écran à une personne malvoyante. Ce comportement est décrit dans les spécifications, avec des règles sur la manière dont l’élément doit fonctionner.</p> <p>Un web-component est un ensemble de technologies permettant aux auteurs d’écrire leurs propres element HTML.</p> <p>En utilisant un simple fichier <code>.js</code>, un web-component regroupe sa structure HTML (le template), son CSS (les styles par défaut) et son comportement (s’il a des intéractions, ce qu’il doit rajouter au html ou tout autre idée encapsulable dans un élément HTML). Et pour l’utiliser, on inclut ce fichier dans une balise script dans notre HTML et voilà, on peut utiliser le web-component.</p> <p>L’un de mes web-components préférés est une prévisualisation de clavier: <a href="https://onedeadkey.github.io/x-keyboard/">x-keyboard</a> (<a href="https://github.com/OneDeadKey/x-keyboard">source</a>). C’est l’outil parfait pour afficher une disposition de clavier à l’écran, et il peut même réagir aux touches réellement tapées par le visiteur.</p> <p><code>paged-page</code> est donc un web-component destiné à afficher la prévisualisation d’une page imprimée à l’écran, en suivant les instructions W3C utilisées pour l’impression.</p> <p>Vous voulez imprimer une page avec un énorme texte au milieu ? Voici le HTML à écrire (je vous laisse le plaisir de choisir le CSS pour centre le texte, il y a trop de solutions possibles, on n’est plus en 2002).</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-page</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Le magasin sera fermé pour Noël. À l’année prochaine !<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-page</span><span class="token punctuation">></span></span></code></pre> <p>Tout le CSS nécessaire à la prévisualisation et à l’impression est inclus dans le composant. Plus besoin de passer trop de temps à retrouver la dernière bonne version.</p> <p>Et nous sommes allés un peu plus loin en ajoutant des attributs pour gérer directement depuis le HTML tout le CSS nécessaire (que l’on trouverait normalement dans un <code>@page</code>) : bleed, marques, marges, largeur et hauteur sont ajoutées en attributs puis transmises au CSS et au HTML.</p> <p>L’un des avantages d’un web-component, c’est qu’il peut être stylé très facilement : il suffit de faire ce que vous feriez avec une balise HTML classique :</p> <pre class="language-css"><code class="language-css"><span class="token selector">paged-page#id</span> <span class="token punctuation">{</span><br> <span class="token property">padding</span><span class="token punctuation">:</span> 3em<span class="token punctuation">;</span><br> <span class="token property">background</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>…et voilà, votre page a maintenant un padding de 3 mm et un fond vert.</p> <p>Plutôt facile, non ? J’espère que vous allez aimer ça, nous sommes vraiment enthousiastes quant aux possibilités que cela va offrir.</p> <h3 id="pages-en-cascade%2C-ou-comment-j%E2%80%99ai-appris-%C3%A0-styliser-le-contenu-%C3%A0-l%E2%80%99int%C3%A9rieur-de-la-page" tabindex="-1">Pages en cascade, ou comment j’ai appris à styliser le contenu à l’intérieur de la page</h3> <p>Conceptuellement, dans le monde du web-to-print, la feuille de papier n’impacte pas la mise en page de son contenu (à part ce que @page peut faire) : en bref, vous ne pouvez pas définir le style du contenu d’une page selon le type de page sur lequel il se trouve.</p> <p>Un exemple simple : supposons que votre design impose que le texte de la treizième page soit d’une autre couleur, sans savoir à l’avance ce qui se trouvera sur cette page. Vous pourriez imaginer écrire :</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span><span class="token punctuation">:</span><span class="token function">nth</span><span class="token punctuation">(</span>13<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br> <span class="token selector">.funny-text</span> <span class="token punctuation">{</span><br> <span class="token property">color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>Eh bien, vous ne pouvez pas. Parce que les spécifications n’autorisent que des propriétés liées à la page dans @page. Vous pouvez définir les marges, le bleed, les marques, la taille de la page… mais pas le style de son contenu.</p> <p>Car cela créerait un problème de cascade : imaginez qu’ailleurs dans votre CSS vous écrivez :</p> <pre class="language-css"><code class="language-css"><span class="token selector">.funny-text</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> yellow <span class="token punctuation">}</span></code></pre> <p>De quelle couleur serait votre texte ?</p> <p>Et imaginez les bizarreries possibles avec la taille du texte : si le texte doit être énorme sur la page 10, mais qu’en devenant énorme il passe à la page 11, que doit-il y avoir sur la page 10 ?</p> <p>Eh bien, paged.js propose une réponse un peu étrange, liée aux transformations qu’il applique aux styles. Tout @page:nth(13) est transformé en classe : @page devient div.paged_page.paged_nth_13, qui accepte le CSS imbriqué et ne pose donc aucun problème pour styliser les éléments enfants, avec une spécificité claire.</p> <p>J’appelle ça la cascade quantique : ça existe et ça n’existe pas, jusqu’au moment où ça apparaît dans la page finale.</p> <p>Mais c’est parfois un jeu de hasard : parfois, vous ne voulez pas que ça arrive, et vous restez coincé avec cette fonctionnalité-qui-n’est-pas-un-bug. Heureusement, dans le monde des web-components, c’est différent. Regardez ce HTML :</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-page</span><br> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-12<span class="token punctuation">"</span></span><br> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id-of-the-page2<span class="token punctuation">"</span></span><br> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">bleed</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">margin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>8mm 14mm<span class="token punctuation">"</span></span><br> <span class="token attr-name">marks</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>cross crop<span class="token punctuation">"</span></span><br><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>Ceci est une page de taille normale.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span> il y aura un peu de contenu ici.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-page</span><span class="token punctuation">></span></span></code></pre> <p>Si je veux changer la couleur du texte, j’ajoute ce CSS :</p> <pre class="language-css"><code class="language-css"><span class="token selector">#page-12</span> <span class="token punctuation">{</span><br> <span class="token property">background</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span><br> <span class="token selector">h2</span> <span class="token punctuation">{</span><br> <span class="token property">color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>Comme vous le voyez, le composant est quasiment invisible : on peut styliser le contenu via la cascade classique.</p> <p>Mais peut-être que je veux modifier le style de la zone de page elle-même. Dans ce cas, il faut rendre le composant visible. C’est justement le rôle du pseudo-élément ::part.</p> <pre class="language-css"><code class="language-css"><span class="token selector">#page-12::part(page-area)</span> <span class="token punctuation">{</span><br> <span class="token property">background</span><span class="token punctuation">:</span> yellow<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>Ça peut sembler anecdotique, parce qu’ici on parle seulement de page-area, mais dès que vous avez des marges, cela devient extrêmement puissant : vous pouvez cibler très profondément dans la structure avec un simple raccourci :</p> <pre class="language-css"><code class="language-css"><span class="token selector">#page-12::part(bottom-center)</span> <span class="token punctuation">{</span> <span class="token property">text-transform</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span> <span class="token property">font-size</span><span class="token punctuation">:</span> .8em <span class="token punctuation">}</span><br><span class="token selector">#page-12::part(bottom-right)::after</span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">counter</span><span class="token punctuation">(</span>page<span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre> <h2 id="r%C3%A9capitulatif" tabindex="-1">Récapitulatif</h2> <p><code>&lt;paged-page&gt;</code> est un composant qui attend les attributs suivants :</p> <ul> <li><code>width</code> : largeur de la page (hors bleed)</li> <li><code>height</code> : hauteur de la page (hors bleed)</li> <li><code>bleed</code> : la quantité de bleed (pour le moment, pas encore de valeurs différentes par côté)</li> <li><code>margin</code> : les marges, écrites exactement comme leur équivalent CSS</li> <li><code>marks</code> : les marques de coupe et de repérage à ajouter</li> </ul> <p>Et puisqu’il s’agit de HTML, vous pouvez ajouter n’importe quel attribut utile à votre code. Par exemple, paged.js ajoutera data-paged-ref pour gérer les sauts de page.</p> <p>Le composant contient trois éléments :</p> <p>les <code>page-marks</code> : pour le bleed et les marques ;</p> <p>les <code>paged-margins</code> : pour accéder rapidement aux margin-boxes via le web-component `paged-margins`` ;</p> <p>la <code>page-area</code> : où apparaît le contenu du composant.</p> <p>Si vous avez plusieurs pages avec plusieurs tailles, l’enregistrement en PDF créera un PDF multi-format.</p> <p>Notez que dans ce cadre, il n’est plus nécessaire d’ajouter le <code>@page</code> au css, puisque tout est fabriqué par le composant HTML.</p> <h2 id="%C3%A0-propos-des-marges" tabindex="-1">À propos des marges</h2> <p>Et tant qu’à avoir la page, on s’est dit, pourquoi pas ajouter les marges, et en faire des web-componants. Comme vous le savez peut-être, dans CSSPrint, il existe 17 emplacements pour intégrer des contenus dans les marges sur une page:</p> <figure><img src="https://pagedjs.org/images/margin-boxes.png"></figure> <p>Les trois quarts du temps, quand on n’utilise pas paged.js, on ne prend pas le temps d’ ajouter les <em>margins-boxes</em>. On finit par utiliser du <code>position: absolute</code> dans notre CSS, sur chaque page, pour aller au plus vite.</p> <p>Mais si la prévisualisation de votre page inclut les marges par défaut, alors il devient facile de les utiliser. Et comme elles sont nécessaires pour paged.js, on les a ajouter au composants (ou plus exactement, on a fabriqué d’autres composants).</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-page</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margins</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-margins<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margin-content</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>top-left<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>le texte courant en haut à gauche<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margin-content</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margin-content</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>top-right<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>en haut à droite<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margin-content</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>paged-margin-content</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>left-top<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>dans la zone le plus haut de la marge de droite.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margin-content</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-margins</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>il y a des marges partout !<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>paged-page</span><span class="token punctuation">></span></span></code></pre> <p>Ici, nous avons une page contenant des marges, et le reste du contenu remplit la page-area.</p> <p>Comme souvent c’est le genre d’outil qui s’apprend en essayant. (dans les semaines qui viennent on va faire pas mal d’exemples, mais tout est là pour que vous puissiez commencer à essayer).</p> <p>Nous espérons que vous allez adorer jouer avec ça ! (et qu’on puisse très vite intégrer tout ce boulot à paged.js)</p> <blockquote> <p>Vous voulez tester rapidement ? Ajoutez simplement ce script à votre HTML et allez commencer à tester des trucs, et n’oubliez pas de venir nous dire comment ça s’est passé pour vous!</p> </blockquote> <pre class="language-html"><code class="language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><br> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>module<span class="token punctuation">"</span></span><br> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/@pagedjs/[email protected]/dist/PagedPreview.js<span class="token punctuation">"</span></span><br> <span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre> <hr> <p>Oh un truc qui n’a rien avoir, mais AntonioJesusBlanco s’est proposé pour traduire la documentation existante en espagnol, et la branche <code>git</code> est prête. <a href="https://github.com/pagedjs/pagedjs/issues/310">https://github.com/pagedjs/pagedjs/issues/310</a></p> <p>venez participer si vous le souhaitez!</p> <p>À très vite.</p> Documenting the update of the documentation 2025-10-16T00:00:00Z https://pagedjs.org/posts/en/documenting-the-update-of-the-documentation/ <p>Folks, today is a big day.</p> <p>We managed to put some time into making a real developper’s documentation using <code>jsdocs</code> comments directly inside the code.</p> <p>As you may have seen, we now have an updated <a href="https://11ty.dev">eleventy</a> with a great multilang setup. Where we can switch from one lang to another, and we can actually get new languages quite easily.</p> <p>And better, we have a setup that will let you add issues, and commits to help us translate (which is, i think, one of the best contribution a project can get.)</p> <p>On the developper’s world, i spent some time adding some <code>jsdocs</code> comments to paged.js and setup the script to generate the new documentation pages when a feature is added.</p> <p>It’s not perfect yet (as Fred needs to read the exising docs to make sure the comments make sense), but the whole mechanism exists, and it’s really cool to see it working that way. <a href="https://pagedjs.org/devdocs/">wink wink</a></p> <p>If you want to contribute, you can actually join us, fork the repo and add features and comments to the code.</p> <p>I’ll come back very soon with some news about Paged.js work around CSS parsing.</p> <p>talk soon!</p> En documentant la mise à jour de la documentation 2025-10-16T00:00:00Z https://pagedjs.org/posts/fr/en-documentant-la-mise-a-jour-de-la-documentation/ <p>Aujourd'hui est un grand jour.</p> <p>D’abord parce que c’est un vendredi et que demain, c’est week-end.</p> <p>Ensuite par ce qu’on a pu avancé sur les questions de documentation de paged.js</p> <p>Mais une chose à la fois.</p> <p>Comme vous l'avez peut-être vu, nous avons maintenant une mise à jour du site fait avec <a href="https://11ty.dev">eleventy</a> (<em>mais c’est tellement bien 11ty</em>), qui est maintenant configuré pour faire du multi langues.</p> <p>Pour l’instant on écrit en français et en anglais par ce que c’est ce qu’on connaît, mais il est très simple de rajouter d’autres langues à la volée et si vous voulez participer, contacter nous <a href="https://pagedjs.org/posts/fr/en-documentant-la-mise-a-jour-de-la-documentation/">[email protected]</a></p> <p>Pour nos amis développeurs, j'ai passé un moment pour ajouter des commentaires <code>jsdocs</code> à paged.js. Et à configurer le script pour générer une mise à jour de la documentation quand une fonctionnalité est ajoutée.</p> <p>C’est pas encore parfait (j’attends que Fred puisse lire mes lignes pour s'assurer ensemble que je ne raconte pas n’importe quoi dans les parties les plus obscures du code), mais tout le mécanisme existe. <a href="https://pagedjs.org/devdocs/">clin d’œil</a></p> <p>Si vous voulez contribuer, vous pouvez nous rejoindre sur le github, ou nous envoyer un mail (<a href="mailto:[email protected]">[email protected]</a>).</p> <p>À très vite.</p> Kickstarting the next iteration of Paged.js 2025-09-16T00:00:00Z https://pagedjs.org/posts/en/kickstarting-the-next-iteration-of-paged.js/ <p>Last week, the paged.js core team kickstarted the work on the next version of paged.js.</p> <p>While Fred stayed in California, Gijs and I were in the office of Open Source Publishing (OSP) in Brussels, where we did quite a lot of things around the future of paged.js.</p> <p><img src="https://pagedjs.org/images/25-09-brussels.jpg" alt="We did meet!"></p> <p>For those who are discovering the world of CSS Print, a couple words about OSP. They are a collective who have been making books and printed stuff using the technologies of the web for a very long time. Such a long time that they even knew CSS-Regions, and even have their own web-kit implementation to support their practices and work.</p> <p>Each member of OSP has been an inspiration and Paged.js wouldn’t be what it is today, if it weren’t for the love and energy they’ve put in the craft. If you don’t know what i’m talking about, a simple glance at the <a href="https://osp.kitchen">osp.kitchen</a> website will give you a good example of where you could find inspiration.</p> <p>I really like the symbol that paged.js <em>neue</em> starts there. Thank you for sharing your office with us.</p> <p>So let’s not spend more time, and let’s get into it.</p> <h3 id="a-quick-recap-of-what%E2%80%99s-on-the-road-map." tabindex="-1">A quick recap of what’s on the road map.</h3> <p>As you may remember, Chrome is now supporting a subset of paged media specifications, most importantly margin-boxes. Unfortunately the browser only supports few of the possibilities described in the specifications: if you want to add running headers, they need to be made by hand, there is no <code>string-set</code> nor <code>position: running</code>, paged.js is still necessary for most of the book design tools we need.</p> <p>When we did our proposal to NLnet to modernize paged.js, here is the list of tasks we put on ourselves.</p> <p>The full roadmap will be soon available on the website.</p> <h3 id="use-web-components-for-reusable-page-elements" tabindex="-1">Use web components for reusable page elements</h3> <p>Paged.js is a big application that has small functions to do a lot of things in many places, and it may be hard for folks to start contributing back. One of the best examples of this is the template which is used when creating a page: it is a very long <a href="https://github.com/pagedjs/pagedjs/blob/703297df075c6f3ba717e04c1de5315d31c3bd60/src/chunker/chunker.js#L14">html string</a> that contains everything: margin boxes, content-area, footnote area, etc.</p> <p>So we decided to look at <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">web components</a> to make parts of the library easier to reuse.<br> The first element we made is the <code>paged-page</code> component that works as a custom print preview html element. It only takes a <code>width</code> and a <code>height</code> attribute and under the hood comes with all the required css to show a preview on screen, and it generates an <code>@page</code> block to instruct the browser on how the document should be printed. In Chrome you can now have multiple page sizes within the same PDF as each page has its own size properties.</p> <p>It’s still undocumented because we’re exploring its API design: should the pages be separate components or <code>slots</code> to fill? Should we have <code>bleed</code> and <code>cropmarks</code> as custom component or are they set through an attribute?</p> <p>But we wanted to share the progress with you, so here we are: you can check the code at the component on the <a href="https://github.com/pagedjs/paged-page">github</a>. We’re halfway through it, and we’ll eventually have a npm package.</p> <p>It has become my main setup to build cssPrint preview, and I hope you’ll enjoy playing with it.</p> <h3 id="use-cssom-for-css-parsing-and-manipulation." tabindex="-1">Use CSSOM for CSS parsing and manipulation.</h3> <p>As you might know paged.js relies on <a href="https://github.com/csstree/csstree">css-tree</a> to convert the CSS as it is described in the standard, and as we write, into CSS supported by browsers. Browsers provide more and more API's for manipulating CSS, mosty notably the CSS Object Model, also known as CSS OM. CSS OM is like the DOM for CSS. It allows for quick CSS inspection and manipulation.</p> <p>We started to explore what is possible with CSS OM by writing the CSS we'd use when making a book. Going through the CSS rules and adding, removing or changing them is so easy that it becomes fun to write CSS with javascript. (note that it’s not CSS in JS, but CSS with JS, we still want to write CSS, not adding another layer of abstraction. TLDR: it’s amazing for things too complex to write in CSS, like generative stuff, but absolutely useless to write your daily CSS).</p> <p>One of the limitations of CSS OM is that you can only access the rendered stylesheet the browser will use to draw things on the page. CSS OM seems to provide access to the styleMap the browser has constructed based on the CSS it has parsed. The browser discards or ignores declarations, selectors and syntax it doesn't support, subsequently they are not accessible through CSS OM. So for example, there is no way to access comments written in the orignal stylesheet. If a CSS declaration has an unknown or unsupported property or value the declaration does not exist in the rendered stylesheet. The browser only manages the properties, values and selectors it knows. In the case of CSSPrint, we work with features that arent’t supported by browsers yet, exactly because paged.js wants to polyfill them. <code>string-set</code>? gone. <code>target-counter</code>? nada <code>@footnote</code>? lol. Until they get included in the list of features the browser support, we can’t have access to it.</p> <p>I believe that manipulating CSS in browsers is better than any preprocessing. To do so, we need to make a conversion layer that will transform a stylesheet into something the browser will understand. Which is exactly what a polyfill is, this is exactly what paged.js is doing.</p> <p>This layer will be a converter that will do a good amount of work:<br> - convert unknown values and properties into CSS custom properties (that we often too quickly call css variables);</p> <ul> <li>replace unknown selectors into usable selectors before they get parsed by the browser.</li> </ul> <p>With the possibility of having nested CSS and CSS custom properties, the amount of work is not that big, as we don’t have to rewrite everything from scratch.</p> <blockquote> <p><strong>A word about browsers</strong><br> As you may have seen, we’re mostly talking about Chrom(e/ium) and derivatives, and that really hurt. Because we believe that paged.js should work in any browser. To do so, we’ll first make it work in Chrome, because that’s where we have fewer features to rebuild, since we can use a lot of what’s already inside. But right after that, we’re moving toward Firefox and Safari and whatever else may appear. It’s a question of energy and <em>folkpower</em> that we can’t really go against right now.<br> But mark those words, we refuse to be one of those Chromium only tool.</p> </blockquote> <h3 id="wpt-printing-test" tabindex="-1">WPT Printing test</h3> <p>The amazing people at Weasyprint built <a href="https://github.com/CourtBouillon/wptprint">a tool</a> to run the <a href="https://web-platform-tests.org/">Web Platform Test suite</a> (WPT) on various tools aimed at making CSS Print. This is an amazing effort that will help all of us, so we want to take part of it. The same way we help writing new specifications we want to support the tooling that allows for better printing.</p> <p>We looked at it with Guillaume from Weasyprint last week, and we’ll participate by using our knowledge to look how we can push it forward. We’ll most likely make some design work, to have improve the UX and UI, and we’ll make sure that the different version of paged.js work fine in there.</p> <h3 id="pagedjs.org-website-updates" tabindex="-1"><a href="http://Pagedjs.org">Pagedjs.org</a> website updates</h3> <p>We’re almost done with this one. You may not have seen it, but we transformed the whole setup for the website by updating to the latest <a href="https://11ty.dev">Eleventy</a>, and we added a multilingual system. We can now write the same post in different languages, and, if you want to participate, you can make a translation of any post (it’s a simple markdown file) and make a Github issue for it. And boom, new language added.</p> <p>We’ll be happy to see you contribute for any language. And if it’s not part of the website, you can contact us, we’ll make it happen :)</p> <p>We still need to have a proper JSdoc export from paged.js repo, for developer’s documentation, <del>and we need to add RSS</del>. (done, I was tired of not having RSS, so I decided to do it before publishing the article 😄 )</p> <h3 id="a-quick-look-at-the-other-tasks" tabindex="-1">A quick look at the other tasks</h3> <h4 id="split-out-content-fragmentation-to-its-own-library" tabindex="-1">Split out content fragmentation to its own library</h4> <p>The goal of this task is to get the chunker out of paged.js. The chunker is the part of the program that finds page breaks and handles the recreation of the HTML tree. Right now, it’s so intertwined with paged.js that it’s hard to reuse it without the paged.js page preview HTML structure. Our idea is that, when the chunker can chunk arbritary content into an arbitrary set of HTML elements, building tools with fragmented content in the browser becomes trivial. (For example chained blocks as we had back in the old days of CSS regions, but with a modern twist in how it would work with CSS).</p> <p>And then, we will update paged.js to use that new library.</p> <h4 id="update-the-fragmentation-method-to-handle-multiple-break-tokens" tabindex="-1">Update the fragmentation method to handle multiple break tokens</h4> <p>Following the previous point, we think it should be possible to have multiple content flows on the same page, with multiple break tokens this becomes much easier than the demo we made for the EPE project (<a href="https://github.com/pagedjs/pagedjs-experiments/blob/main/--paged-parallel-flows/parallel-flows.js">https://github.com/pagedjs/pagedjs-experiments/blob/main/--paged-parallel-flows/parallel-flows.js</a>).</p> <h4 id="tagged-pdf-support" tabindex="-1">Tagged PDF support</h4> <p>Yeah, that’s one of the hardest, but we want to provide some tagged pdf with paged.js. It’s a long term work, but we have that in mind on every step to make sure everything can work as expected.</p> <p>So that’s what we did.</p> <hr> <p>Starting in a couple of weeks, we’ll provide more frequent but smaller updates on what we’re doing and where we are, as we’re starting to look at options to support the effort on the long run.</p> <hr> <p>Have a great couple of weeks</p> Parallel-flows within Paged.js 2025-07-26T00:00:00Z https://pagedjs.org/posts/en/parallel-flows-within-paged.js/ <p>While it is easy to imagine a multilingual book that would share its pages to accommodate content in two languages, it has always been difficult to imagine the web other than this long vertical flow, heir to the wheel. The content of a page starts at the top, and ends, when there is no more content to be placed on the page, well below what the screen shows, giving each illusion of infinity, what the attention economists have well integrated into their tools.</p> <p>In reality, we have imagined some subterfuges to offer a semblance of parallel flow, from the layout through the `table' to the appearance of CSS or Flex grids, but it is always about the same downward movement, and even if the magic trick is invisible, because remarkably realized, it comes to mind when we wish to translate it on a paginated media.</p> <h2 id="the-unfulfilled-promise-of-css-regions" tabindex="-1">The unfulfilled promise of CSS regions</h2> <p>When W3C editors work on the specifications for print, the web is not yet a world of <em>web apps</em>, of overpowered CSS and layout automation. We barely get out of the <code>&lt;table&gt;</code> layouts and we’re just discovering the wonderful world of <em>floats</em>. It is still <em>The web of the document</em> for which a page has a beginning (top) and an end (bottom). Suffice to say that when one thinks about printed matter, they do not look much further than to cut this flow into a sequence of pages until to form, for the most insane minds, a book.</p> <p>Well, in fact, there have been attempts, one of which has been quite extensive: the CSS regions. This technique allowed the definition of spaces in which previously dissociated content streams could flow into the HTML code. And it was all but simple: the HTML was divided into two parts: on one hand the content, and on the other hand the container, associated with a complex CSS that defined the positioning of the boxes, and the shape of their contents. Yes that sentence was as complex as using css regions was. I will not go back here to the reasons why people in Chromium gave up the idea, because it would be too long and subject to so much controversy that we would lose the day (and a little mental health) arguing.</p> <p>Just know that, within a few years, we had CSS regions in Chrome and we knew how to use them, and we made amazing things with it.</p> <p>Moreover, Open Source Publishing, to which the CSS Print owes a great deal, has shown more than once the interest of such a practice. I think the best example comes from <a href="https://osp.kitchen/work/the-riddle/"><em>The Riddle</em></a>.</p> <p><img src="https://pagedjs.org/images/theriddle.png" alt="A reproduction of the book The Riddle designed by Open Source Publishing, web2print, showing two independent text streams that share the page."></p> <h2 id="and-css-grid-was." tabindex="-1">And CSS Grid was.</h2> <p>If you look at the CSS presentation videos, the ones produced to push them into adoption, you always find the idea that it is about finding artifices of layouts that come from the book. And especially graphic experiments that come straight from the magazine press.</p> <p>The CSS grid is the total step of the separation between the content and its form. If before these properties, the HTML was to give the order according to which items should be displayed on the page, this is not necessarily the case today, since the CSS offers authors the possibility to define, in addition to their form, the positioning and order of these contents.</p> <p>The simplest way to look at a CSS grid is to see a touch-and-tip tray. To place each vessel, simply give its horizontal and vertical coordinates on a 2D grid. Therefore, the reading order is no longer descending, it is multiple, and depends on the organization of the page induced by the CSS.</p> <p>However, the CSS grid has a fundamental limitation: no element can be separated into two blocks from this grid. The following image shows something impossible in CSS:</p> <p><img src="https://pagedjs.org/images/blocalautre.jpg" alt="Textual content separated between two text blocks"></p> <h2 id="the-print-as-a-trojan-horse" tabindex="-1">The print as a Trojan horse</h2> <p>The good thing about CSS print is that unlike the web, we are working on a page with limited dimensions, and that it is up to us to make the graphic and typographical decisions that allow the cutting of a long text into an infinity of smaller ones. Even if the W3C specifications show that questions have arisen and answers may have appeared, it is certain that the translation into print is an understatement of the evolution of the web.</p> <p>First because print is only a limited use of our digital life and then because it would pose a thorny question: if we do it for a paginated media, why don't we do it for the web? If a printed CSS grid should allow the cutting of content on several cells, then why can't we afford it on the screen?</p> <p>An interesting thing to do when a practice does not seem to exist on the web is to invest the field and start thinking about solutions, abstract enough to be reusable and clear enough to be explained, commented and analyzed.</p> <p>The question of multiflux is difficult whatever the media, but it is the paginated media that seems to need the most answers, since unlike the screen, the paper is not infinite. Hence, here is a feedback on the multiflux in paged.js, organized around the project Screen Paper Edit, (EPE), led by l'Esad Grenoble / Valencia.</p> <p>As part of the project, designers needed a solution to put texts in several languages and deal with them in the same way, avoiding placing one before the other. Perfect starting point to put the question of CSS regions on the table, now that CSS grids have become a central tool in web design habits.</p> <p>pagedjs-multiple-flows.0.1d.js</p> <blockquote> <p>If you want to take a look at the code first, it is here: <a href="https://github.com/pagedjs/pagedjs-experiments/tree/main/--paged-parallel-flows">parallel-flows</a>. As i’m writing this, we’re on version 0.1d, working with paged.js 0.4.3 and 0.5b</p> </blockquote> <p><code>paged.js parallel-flows</code> is a Paged.js plugin that allows you to define so-called parallel streams (in the absence of a better name). The idea is to use CSS to define streams that will share a space, whether it is a page (several languages on the same page), or a double page (where each language has its own page).</p> <p>It looks like this:</p> <p><img src="https://pagedjs.org/images/betterapig.jpg" alt="A layout of two flows on the same page, using paged.js"></p> <p>To do this, we use a custom CSS property we made, called <code>--paged-parallel-flow</code>. This property expects for value the name of a stream that will serve as an identifier. All elements that have the same value for this property will therefore be part of the same parallel flow.</p> <p>Take this HTML for example:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alpha<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>content<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>beta<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>content<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>delta<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>content<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>epsilon<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>content<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></code></pre> <p>and this CSS:</p> <pre class="language-css"><code class="language-css"><br><span class="token selector">#alpha</span> <span class="token punctuation">{</span><br><span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> hand<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 30%<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#beta</span> <span class="token punctuation">{</span><br><span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> hand<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 65%<span class="token punctuation">;</span><br><span class="token property">margin-left</span><span class="token punctuation">:</span> car<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#epsilon</span> <span class="token punctuation">{</span><br><span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> else<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 45%<span class="token punctuation">;</span><br><br><span class="token punctuation">}</span><br><br><span class="token selector">#delta</span> <span class="token punctuation">{</span><br><span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> else<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 45%<span class="token punctuation">;</span><br><span class="token property">margin-left</span><span class="token punctuation">:</span> car<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>Note that each element already has investment properties: <code>#alpha</code> has a 30% width of its parent, <code>#beta</code> 65% and will be placed to the right, thanks to the use of <code>margin-left: auto</code>. The blocks defined here are therefore the locations of the containers as much as the contents.</p> <p><code>#alpha</code> and <code>#beta</code> must be treated at the same time and share one space, <code>#epsilon</code> and <code>#delta</code> share another.</p> <h3 id="the-configuration-of-javascript" tabindex="-1">The configuration of javascript</h3> <p>The javascript expects a specific configuration that informs about the type of flow and the choices of its implementation</p> <p>The type of flow:</p> <ul> <li><code>samepage</code>: streams share the same pages</li> <li><code>samespread</code>: streams share the same double page</li> </ul> <pre class="language-javascript"><code class="language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>flowLocation <span class="token operator">=</span> <span class="token string">"samespread"</span><span class="token punctuation">;</span></code></pre> <p>or</p> <pre class="language-javascript"><code class="language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>flowLocation <span class="token operator">=</span> <span class="token string">"samepage"</span><span class="token punctuation">;</span></code></pre> <p>In the case of streams that would be configured to use <code>samespread</code>, you can automatically add a blank page if the streams are not of the same length.</p> <pre class="language-js"><code class="language-js"><span class="token keyword">this</span><span class="token punctuation">.</span>flowSpreadAddWhite <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></code></pre> <h3 id="what's-happening." tabindex="-1">What's happening.</h3> <ol> <li> <p>Paged.js finds the starting point of each flow and marks the first element as the starting point of the parallel flow.</p> </li> <li> <p>Paged.js draws the two elements by following the CSS rules, to find the longest. This then becomes the main flow of this stream, and it is moved before the first element of the stream. Secondary streams are sent all at the end of the content to be processed in a second time.</p> </li> <li> <p>Once the entire content has been paged, Paged.js finds each main stream and returns the secondary stream elements to the same pages (or adjacent pages in the case of a <code>samespread</code>), before deleting the pages that are now empty. Note: if it is a <code>samespread</code>, the pages are directly moved.</p> </li> </ol> <p><img src="https://pagedjs.org/images/flows.jpg" alt=""></p> <p>Bonus, an experiment.</p> <p>Sometimes the main stream contains images. And it is not uncommon to want these images to exceed the width of text, without necessarily encroaching on the space needed for another stream. For this, we use <code>--paged-parallel-impact: all</code>. This experimental feature allows the main flow elements to impact the formatting of secondary flows. One case of use: an image dressed in the first stream, could dress the second. From a technical point of view, an invisible floating element is added at the beginning of this secondary flow, on the page or element A exists. This new item can be selected in CSS.</p> <p>It is possible that the position of the added element is not correct, which is why it is possible to add the necessary changes to the css. To do this, you need to find the element identifier and add <code>-overlap</code> to your id.</p> <p>For example:</p> <pre class="language-css"><code class="language-css"><span class="token selector">#porco</span> <span class="token punctuation">{</span><br>--paged-parallel <span class="token property">impact</span><span class="token punctuation">:</span> all<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>To modify the manufactured overlap element, e.g. in the <code>#alpha</code> secion:</p> <pre class="language-css"><code class="language-css"><span class="token selector">#alpha #porco-overlap</span> <span class="token punctuation">{</span><br><span class="token property">width</span><span class="token punctuation">:</span> 350px<span class="token important">!important</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <ul> <li><code>--paged-parallel impact</code> works only if the image is in the main stream, since it is it that is set up before the others, and therefore cannot be modified thereafter. Reminder: the main stream is automatically detected, it is the most<br> long (taking into account objects and images). To do this, the script makes a first layout pass before sinking the content for good.</li> </ul> <h3 id="one-last-thing" tabindex="-1">One last thing</h3> <p>Raphael, who’s testing the implementation is a smart mind, and like all developper as some very existencial issues, like: how to not have to redo the whole html to break the content is smallest bit to make sure they can be correctly set on the pages.</p> <p>So he came up with the idea of parallel-sync. If you have two pieces of content you want to show next to each other, and they’re both one long string of HTML, you can use another custom property.</p> <pre class="language-css"><code class="language-css"><span class="token selector">.en,.fr</span> <span class="token punctuation">{</span><br> <span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> alpha<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token selector">h3</span><span class="token punctuation">{</span><br><span class="token property">--paged-parallel-sync</span><span class="token punctuation">:</span> alpha<span class="token punctuation">;</span> <br><span class="token punctuation">}</span></code></pre> <p>So if you have <code>h3</code> in the different flows, they’ll wait for each other to start on the same page.</p> <blockquote> <p>If you want to take a look at the code, it is here: <a href="https://github.com/pagedjs/pagedjs-experiments/tree/main/--paged-parallel-flows">parallel-flows</a>. As i’m writing this, we’re on version 0.1d, working with paged.js 0.4.3 and 0.5b</p> </blockquote> Flux parallel avec Paged.js 2025-07-26T00:00:00Z https://pagedjs.org/posts/fr/flux-parallel-avec-paged.js/ <p>S’il est facile d’imaginer un livre multilingue qui partagerait ses pages pour y accueillir les contenus dans deux langues, il a toujours été difficile d’imaginer le web autrement que ce long flux vertical, héritier de la molette. Le contenu d’une page démarre en haut, et se termine, lorsqu’il n’y a plus de contenu à poser sur la page, bien en-desssous de ce que l’écran laisse entrevoir, donnant à chacune l’illusion de l’infini, ce que les économistes de l’attention ont bien intégré à leurs outils.</p> <p>En réalité, nous avons bien imaginé des subterfuges pour proposer un semblant de flux parallèle, de la mise en page grâce aux <code>table</code> jusqu’à l’apparition des grilles CSS ou de Flex, mais il s’agit toujours de ce même mouvement descendant, et même si le tour de magie est invisible, parce que remarquablement réalisé, il saute aux yeux dès lors qu’on souhaite le traduire sur un média paginé.</p> <h2 id="la-promesse-non-tenue-des-r%C3%A9gions-css" tabindex="-1">La promesse non tenue des régions CSS</h2> <p>Quand les éditeurs du W3C travaillent sur les spécifications pour l’imprimé, le web n’est pas encore un monde de <em>web apps</em>, de CSS surpuissantes et d’automatisations de mise en page. On sort à peine des layouts de <code>&lt;table&gt;</code> et on découvre le monde merveilleux des <em>floats</em> (de l’habillage de texte, très conditionnel). C’est encore le web du document pour lequel une page a un début (en haut) et une fin (en bas). Autant dire que quand on pense l’imprimé, on ne cherche pas beaucoup plus loin que de découper ce flux en une suite de pages jusqu’à former, pour les esprits les plus fous, un livre.</p> <p>Bon, en vrai, y a eu des tentatives, dont une assez poussée : les régions CSS. Cette technique permettait de définir des espaces dans lesquels faire couler des flux de contenu auparavant dissociés dans le code HTML. Et c’était tout sauf simple : l’HTML était divisé en deux : d’une part le contenu, et d’autre part le contenant, associé à un CSS complexe qui définissait les positionnements des boites, et la forme de leur contenu. Je ne reviendrai pas ici sur les raisons qui ont poussé les gens de Chromium à abandonner l’idée, par ce que ce serait trop long et sujet à tellement de controverses qu’on y perdrait la journée (et un peu de santé mentale). Sachez simplement que, l’espace de quelques années, nous avions des régions CSS dans Chrome et que nous avions su nous en servir.</p> <p>Et d’ailleurs, Open Source Publishing, à qui le CSS Print doit énormément, a montré plus d’une fois l’intérêt d’une telle pratique. Je crois que le meilleur exemple vient de <a href="https://osp.kitchen/work/the-riddle/"><em>The Riddle</em></a>.</p> <p><img src="https://pagedjs.org/images/theriddle.png" alt="Une reproduction du livre The Riddle conçu par Open Source Publishing, en web2print, qui montre deux flux de texte indépendants qui partagent la page."></p> <h2 id="et-css-grid-fut." tabindex="-1">Et CSS Grid fut.</h2> <p>Si on regarde les vidéos de présentation des grilles CSS, celles produites pour pousser à leur adoption, on retrouve toujours mentionnée l’idée qu’il s’agit de retrouver des artifices de mises en page qui viennent du livre. Et en particulier des expérimentations graphiques qui viennent tout droit de la presse magazine.</p> <p>La grille CSS est l’étape totale de la séparation entre le contenu et sa forme. Si avant ces propriétés, le HTML se devait de donner l’ordre selon lequel devaient s’afficher des éléments sur la page, ce n’est plus forcément le cas aujourd’hui, puisque le CSS offre la possibilité aux auteurs de définir, en plus de leur forme, le positionnement et l’ordre de ces contenus.</p> <p>La façon la plus simple de regarder une grille CSS, c’est de voir un plateau de touché-coulé. Pour y déposer chaque bateau, il suffit de donner ses coordonnées horizontales et verticales sur une grille en 2D. Dès lors, l’ordre de lecture n’est plus descendant, il est multiple, et dépend de l’organisation de la page induite par le CSS.</p> <p>Pour autant, la grille CSS a une limitation fondamentale : aucun élément ne peux être séparé en deux blocs de cette grille. L’image suivante démontre quelque chose d’impossible en CSS :</p> <p><img src="https://pagedjs.org/images/blocalautre.jpg" alt="Un contenu textuel séparé entre deux blocs de texte"></p> <h2 id="le-print-comme-cheval-de-troie" tabindex="-1">Le print comme cheval de Troie</h2> <p>Le bon côté du CSS print, c’est que contrairement au web, on travaille sur une page dont les dimensions sont limitées, et qu’il nous appartient de prendre les décisions graphiques et typographiques qui autorisent la coupe d’un long texte en une infinité de plus petits. Même si les spécifications du W3C montrent que des questions se sont posées et que des réponses ont pu apparaître, il est certain que la traduction en imprimé est un impensé des évolutions du web.</p> <p>D’abord parce que l’imprimé ne représente qu’un usage limité de notre vie numérique et ensuite par ce que cela viendrait poser une question épineuse : si on le fait pour un média paginé, pourquoi est-ce qu’on ne le ferait pas pour le web ? Si une grille CSS imprimée doit permettre la coupe d’un contenu sur plusieurs cellules, alors pourquoi est-ce qu’on ne peut pas se le permettre à l’écran ?</p> <p>Une chose intéressante à faire lorsque qu’une pratique n’a pas l’air d’exister sur le web, c’est d’investir le champ et de commencer à réfléchir à des solutions, suffisamment abstraites pour être réutilisables et assez claires pour être expliquées, commentées et analysées.</p> <p>La question du multiflux est difficile quelque soit le média, mais c’est le média paginé qui semble avoir le plus besoin de réponses, puisque contrairement à l’écran, le papier n’est pas infini. Dès lors, voici un retour d’expérience sur le multiflux dans paged.js, organisé autour du projet Écran Papier Éditer, (EPE), mené par l’Ésad Grenoble / Valence.</p> <p>Dans le cadre du projet, les designers ont eu besoin d’une solution pour mettre en page des textes en plusieurs langues et les traiter avec les mêmes égards, en évitant d’en placer une avant l’autre. Parfait point de départ pour remettre la question des régions CSS sur la table, maintenant que les grilles CSS sont devenues un outil central dans les habitudes de web design.</p> <h2 id="pagedjs-parallel-flows" tabindex="-1">pagedjs-parallel-flows</h2> <blockquote> <p>Si vous voulez d’abord jeter un coup d’œil au code, il se trouve ici : <a href="https://github.com/pagedjs/pagedjs-experiments/tree/main/--paged-parallel-flows">https://github.com/pagedjs/pagedjs-experiments/tree/main/--paged-parallel-flows</a>.</p> </blockquote> <p>`paged.js multi-flows est un plugin Paged.js qui permet de définir des flux dits parallèles (à défaut d’un meilleur nom). L’idée est d’utiliser le CSS pour définir des flux qui partageront un espace, que ce soit une page (plusieurs langues sur la même page), soit une double page (où chaque langue a sa propre page).</p> <p>Ça ressemble à ça :</p> <p><img src="https://pagedjs.org/images/betterapig.jpg" alt="A layout of two flows on the same page, using paged.js"></p> <p>Pour ce faire, nous utilisons une propriété CSS inventé pour l’occasion, que nous appellerons <code>--paged-parallel-flow</code>. Cette propriété attend pour valeur le nom d’un flux qui servira d’identifiant. Tous les éléments qui possèdent la même valeur pour cette propriété feront donc partie du même flux parallèle.</p> <p>Prenons par exemple ce HTML :</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alpha<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>contenu<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>beta<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>contenu<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>delta<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>contenu<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>epsilon<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>contenu<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></code></pre> <p>et ce CSS :</p> <pre class="language-css"><code class="language-css"><br><span class="token selector">#alpha</span> <span class="token punctuation">{</span><br> <span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> main<span class="token punctuation">;</span><br> <span class="token property">width</span><span class="token punctuation">:</span> 30%<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#beta</span> <span class="token punctuation">{</span><br> <span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> main<span class="token punctuation">;</span><br> <span class="token property">width</span><span class="token punctuation">:</span> 65%<span class="token punctuation">;</span><br> <span class="token property">margin-left</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#epsilon</span> <span class="token punctuation">{</span><br> <span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> else<span class="token punctuation">;</span><br> <span class="token property">width</span><span class="token punctuation">:</span> 45%<span class="token punctuation">;</span><br><br><span class="token punctuation">}</span><br><br><span class="token selector">#delta</span> <span class="token punctuation">{</span><br> <span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> else<span class="token punctuation">;</span><br> <span class="token property">width</span><span class="token punctuation">:</span> 45%<span class="token punctuation">;</span><br> <span class="token property">margin-left</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>Notez que chaque élément possède déjà des propriétés de placement : <code>#alpha</code> a une largeur de 30% de son parent, <code>#beta</code> de 65% et sera placé à droite, grâce à l’utilisation de <code>margin-left: auto</code>. Les blocs définis ici sont donc les emplacements des contenants autant que les contenus.</p> <p><code>#alpha</code> et <code>#beta</code> devront être traités en même temps et partager un espace, <code>#epsilon</code> et <code>#delta</code> en partagent un autre.</p> <h3 id="la-config-du-javascript" tabindex="-1">La config du javascript</h3> <p>Le javascript attend une configuration spécifique qui informe sur le type de flux et sur les choix de sa mise en place</p> <p>Le type de flux:</p> <ul> <li><code>samepage</code> : les flux partagent les mêmes pages</li> <li><code>samespread</code> : les flux partagent la même double page</li> </ul> <pre class="language-javascript"><code class="language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>flowLocation <span class="token operator">=</span> <span class="token string">"samespread"</span><span class="token punctuation">;</span></code></pre> <p>ou</p> <pre class="language-javascript"><code class="language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>flowLocation <span class="token operator">=</span> <span class="token string">"samepage"</span><span class="token punctuation">;</span></code></pre> <p>Dans le cas de flux qui seraient configurés pour utiliser <code>samespread</code>, on peut automatiquement ajouter une page blanche si les flux ne sont pas de même longueur.</p> <pre class="language-js"><code class="language-js"><span class="token keyword">this</span><span class="token punctuation">.</span>flowSpreadAddWhite <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></code></pre> <h3 id="ce-qui-se-passe." tabindex="-1">Ce qui se passe.</h3> <ol> <li> <p>Paged.js trouve le point de départ de chaque flux et en marque le premier élément comme le point de départ du flux parallèle.</p> </li> <li> <p>Paged.js dessine les deux éléments en suivant les règles de CSS, pour trouver le plus long. Celui ci devient alors le flux principal de ce flux, et il est déplacé avant le premier élément du flux. Les flux secondaires sont envoyés tout à la fin du contenu pour être traités dans un second temps.</p> </li> <li> <p>Une fois la totalité du contenu mis en page, Paged.js retrouve chaque flux principal et ramène les éléments des flux secondaires sur les mêmes pages (ou sur les pages adjacentes dans le cas d’un <code>samespread</code>), avant de supprimer les pages qui sont maintenant vides. Note : s’il s’agit d’un <code>samespread</code>, les pages sont directement déplacées.</p> </li> </ol> <p><img src="https://pagedjs.org/images/flows.jpg" alt=""></p> <h3 id="bonus%2C-une-exp%C3%A9rimentation." tabindex="-1">Bonus, une expérimentation.</h3> <p>Il arrive que le flux principal contienne des images. Et il n’est pas rare de vouloir que ces images dépassent de la largeur de texte, sans forcément empiéter sur l’espace nécessaire à un autre flux. Pour cela, on utilise <code>--paged-parallel-impact: all</code>. Cette fonctionnalité expérimentale permet d’autoriser les éléments du flux principal à impacter la mise en forme des flux secondaires. Un cas d’usage : une image en habillage du premier flux, pourrait habiller le second. D’un point de vue technique, un élément invisible flottant est rajouté au début de ce flux secondaire, sur la page ou l’élément A existe. Ce nouvel élément peut être sélectionné en CSS.</p> <p>Il est possible que le positionnement de l’élément rajouté ne soit pas correct, c’est pourquoi il est possible de rajouter dans le css les changements nécessaire. Pour cela, il faut retrouver l’identifiant de l’élément et rajouter <code>-overlap</code> dans son id.</p> <p>Par exemple:</p> <pre class="language-css"><code class="language-css"><span class="token selector">#porco</span> <span class="token punctuation">{</span><br> <span class="token property">--paged-parallel-impact</span><span class="token punctuation">:</span> all<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>Pour modifier l’élément overlap fabriqué, par exemple dans la secion <code>#alpha</code> :</p> <pre class="language-css"><code class="language-css"><span class="token selector">#alpha #porco-overlap</span> <span class="token punctuation">{</span><br> <span class="token property">width</span><span class="token punctuation">:</span> 350px <span class="token important">!important</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <ul> <li><code>--parallel impact</code> ne marche qu’à condition que l’image soit dans le flux principal, puisque c’est lui qui est mis en page avant les autres, et qu’il ne peut donc pas être modifié par la suite. Rappel : le flux principal est automatiquement détecté, il s’agit du flux le plus<br> long (en prenant en compte les objets et images). Pour ce faire, le script fait une première passe de mise en page avant de couler le contenu pour de bon.</li> </ul> <h3 id="une-derni%C3%A8re-chose" tabindex="-1">Une dernière chose</h3> <p>Raphael, qui teste l'implémentation est un esprit intelligent, et comme tous les développeurs comme certains problèmes très existentencial, comme: comment ne pas avoir à refaire le html entier pour casser le contenu est plus petit peu pour s'assurer qu'ils peuvent être correctement définis sur les pages.</p> <p>Il a donc eu l'idée de synchroniser les titres, et nous sommes arrivés tous les deux à une solution ``--paged-parallel-sync`.</p> <p>Si vous avez deux morceaux de contenu que vous voulez afficher à côté de l'autre, et qu'ils sont tous les deux dans deux éléments HTML distincs. Vous pouvez vous assurer que les titres démarrent tous sur la même page.</p> <pre class="language-css"><code class="language-css"><span class="token selector">.en,.fr</span> <span class="token punctuation">{</span><br> <span class="token property">--paged-parallel-flow</span><span class="token punctuation">:</span> alpha<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br> <br><span class="token selector">h3</span> <span class="token punctuation">{</span><br><span class="token property">--paged-parallel-sync</span><span class="token punctuation">:</span> alpha<span class="token punctuation">;</span> <br><span class="token punctuation">}</span></code></pre> <blockquote> <p>Si vous voulez enfin jeter un coup d’œil au code, il se trouve ici : <a href="https://github.com/pagedjs/pagedjs-experiments/tree/main/--paged-parallel-flows">https://github.com/pagedjs/pagedjs-experiments/tree/main/--paged-parallel-flows</a>.</p> </blockquote> A new chapter in Paged.js life 2025-05-17T00:00:00Z https://pagedjs.org/posts/en/a-new-chapter-in-paged.js-life/ <p>I can still picture the room where Adam Hyde put Fred Chasen and myself around the table, looking at options for making PDF from HTML, and, while we couldn’t find a way that was satisfying enough, he looked at us, and said: “let’s just make it”.</p> <p>And then we started. Very early in the process Julie Blanc joined, and within a couple of months we had a working proof of concept. In not so much more; a full fledge library. All of this was possible thanks to all the energy and resources Adam Hyde and Coko put into the project.</p> <p>At that time the goal of paged.js was to show how CSSPrint could make single source publishing a reality. Most of our work was about helping folks who wanted to implement paged.js in their workflows, or build use cases around it and we were spending a lot of energy on workshops, book fairs, user support and demo projects. Plus, with the <a href="https://pagedjs.org/en/documentation/10-handlers-hooks-and-custom-javascript/">hook systems</a>, people would extend the functionality of paged.js with their own scripts and manage to create amazing publications: from vote ballots, to complex (almost) automatic layouts. We were mostly helping folks implementing complex algorithms for print or even implementing some of it ourselves.</p> <p>At some point, we were doing more work to help users with paged.js than we spent updating paged.js' core code, features or documentation nor kept the community in the loop of what’s happening.</p> <p>So let’s change that, welcome to paged.js 2.0</p> <h2 id="didn%E2%80%99t-you-skip-a-number%3F-where-is-1.0%3F" tabindex="-1">Didn’t you skip a number? Where is 1.0?</h2> <p>The idea we had with paged.js was that, at some point, the browser would do the work of supporting paged media specifications and folks could get rid of paged.js all together, simply use the browser for all their pdf needs, and we could stop working on it. The goal of the project was to render itself ultimately redundant. But what we discovered on the path is that paged.js is more than a polyfill for future features, it’s also a gateway to css print because of the preview you get on the screen.</p> <p>In short, when you use paged.js, the library will take your html and css, find all the properties used for print (@page, margin-boxes, target-counter, etc.), and replace them with html and css to preview, on screen, what will appear on paper (or in the PDF). This allows you to inspect your pages, look at the css, test changes in context and run paged.js again. And print from the browser, which doesn’t use the css for print, but the converted css you have on the screen.</p> <p>And then, Chromium team did what we wanted them to do before paged.js: they started to implement print features, <a href="https://developer.chrome.com/blog/new-in-chrome-131">starting with the margin-boxes</a>. Hopefully, it will push other engines to do the same. But, in the meantime, things get tricky for paged.js.</p> <p>Supporting chromium updates would mean transforming paged.js in such a way that firefox or other browsers would be left behind, which goes against our goals. Yes, we did repeat that chromium was better because it allows for custom page sizes and manage widows and orphans better, but Firefox, or Safari, or any other browser would still be a valid option.</p> <p>Therefore paged.js needs to change to support more engines and more contexts of use. As this is a breaking change we’ll jump to paged.js 2.0 very quickly.</p> <h2 id="so-long-paged.js%2C-hello-paged.js-neue" tabindex="-1">So long paged.js, hello paged.js neue</h2> <p>First, paged.js members are part of a NGIzero supported project, <a href="https://nlnet.nl/project/CSS-Print/">Pushing forward for CSS Print</a>, for which we’re joining force with the lovely Lucie and Guillaume of Weasyprint (a python based engine to make PDF out of HTML and CSS) to push #CSSprint forward. We’ll write down new specifications to print with CSS and implement them in weasyprint and paged.js, in order to push the conversation forward with the W3C folks. (You can check our <a href="https://github.com/w3c/csswg-drafts/issues/12472">Notes on notes</a> to see some examples of what we could do).</p> <p>Second, Paged.js has also been accepted for a NGIzero grant to support the important structural update of paged.js and its dependencies. This plan of update includes a lot of breaking changes: removing CSSTree to replace it with cssOM, use web-components for pages, and document, transform the chunker into its own library, change the algorythm that find breaktoken, allows for multiple break tokens, etc. We’ll cover more of that in the future updates on the blog, as soon as we have a proper calendar to share. The grant is only available for a year so that’s already a nice information.</p> <h3 id="meet-the-team" tabindex="-1">Meet the team</h3> <p>First, Gijs de Heij is joining the team as a core maintainer. While Fred is working a fulltime position at Mozilla, we decided to redraw how the team works around paged.js. Instead of putting everything of Fred’s shoulders, we’re moving toward a team of core developers, as Gijs and myself will be more involved into paged.js development by contributing codes, features and managing user support.</p> <p>Gijs is an amazing designer / developer and a member of the collective Open Source Publishing, he’s been a long time user of paged.js and experienced first hand what works, what doesn’t, and what needs a work around.</p> <p>As Fred’s time is reduced, his work on paged.js will be less visible, and though Julie officially stopped working on paged.js when she started working on her thesis she’s still around paged.js and part of the Weasyprint × Paged.js project. By now she's Julie Blanc, PhD, afters she defended her thesis <a href="http://phd.julie-blanc.fr/">“Composer avec les technologies du web ”</a> (<em>Composing with web technologies. Collective instrumental genesis for the development of a community of practice of graphic designers</em>), it observes how paged.js was used by graphic designers to share knowledge and build communities.</p> <p>Coko has been supporting paged.js for all of us for a long time, and we wouldn’t be where we are now if it wasn’t for Adam Hyde’s time, energy, trust and generosity. I don’t think I’ll ever be able to thank him enough for all the support he gave to each one of us. And even though Coko is not financially supporting paged.js anymore, Adam is still around to help, and we wouldn’t like it any other way.</p> <h3 id="on-paged.js-future" tabindex="-1">On paged.js future</h3> <p>This post is already too long. So, to not take too much of your time, some final practical updates:</p> <ul> <li>Paged.js now has a mastodon account on fosstodon: <a href="https://fosstodon.org/@pagedjs">https://fosstodon.org/@pagedjs</a>, we won’t be using twitter anymore.</li> <li>Paged.js code (and submited issues) are now on github, as well as the sources for this website, and we’re slowly bringing back some of the plugins and snippets we developed here and there. (<a href="https://github.com/pagedjs/">https://github.com/pagedjs/</a>)</li> <li>You can reach us by email: <a href="mailto:[email protected]">[email protected]</a></li> <li>Paged.js now has a Matrix channel. Come to chat and discuss the futur with us: <a href="https://matrix.to/#/#pagedjs:matrix.org">https://matrix.to/#/#pagedjs:matrix.org</a></li> <li>The website is now fully internationalized. Thanks for the amazing amazing (not a typo, i wrote it twice) <a href="https://11ty.dev">Eleventy</a>. You can now join the translation effort if you feel like it :D.</li> </ul> <p>There are a bunch of other things to share in the coming weeks, from pagedjs structural changes to documentation update/rewriting (for devs &amp; users), and other things we want to bring back (plugins, templates, etc.)</p> <p>With the hope that you’ll want to take part in Paged.js future, as you may have done before.</p> <p>See yall very soon.</p> Le prochain chapitre de Paged.js 2025-05-17T00:00:00Z https://pagedjs.org/posts/fr/le-prochain-chapitre-de-paged.js/ <p>Je me souviens précisément de la pièce où, accompagné d’Adam Hyde et de Fred Chasen, nous regardions les possibilités existantesp pour transformer du HTML en PDF, et alors qu’on ne trouvait rien de probant, Adam s’est arrêté, nous a regardé et à dit : <em>Let’s just make it</em>.</p> <p>Et nous voilà partis. Julie Blanc nous a rejoint très vite, et au bout de quelques mois nous avions un preuve de concept fonctionnelles, et en moins d’un an, une bibliothèque javascript capable de produire des PDF. Rien de tout ça n’aurait pu être possible si Adam et Coko n’avaient pas autant investi de temps et de ressources dans le projet.</p> <p>Les années qui ont suivi ont surtout été le moment de mettre le <em>CSS Print</em> sur le devant de la scène, comme pierre angulaire du <em>single source publishing</em>. La majorité de notre travail consistait à accompagner les utilisateurs de paged.js, que ce soit pour de accompagner des implémentations &amp; des workflows, former des designers et des éditeurs aux concepts de <code>web to print</code>, participer à des salons du livres et évenements professionnels, et, lorsqu’il restait un peu de temps, accompagner des projets de livres numériques multi-formats.</p> <p>Avec Paged.js et son système de hooks, on a vu apparaître une quantité importante de documents produits avec Paged.js, qu’il s’agisse de rapports scientifiques, de bulletins de vote US, d’articles scientifique à la mise en page quasi automatique, et c’est avec une grande fierté que nous avons pu participer à quelques-uns de ces chantiers.</p> <p>Mais ce travail a un coût et si on a pu accompagner des projets, nous n’avons pas été des plus efficace pour tenir au courant la communauté des changements, mises à jour et autres expérimentations.</p> <p>Il est temps de changer ça et de passer à paged.js 2.0</p> <h2 id="2.0-%3F-mais-o%C3%B9-est-pass%C3%A9-la-1.0-%3F" tabindex="-1">2.0 ? Mais où est passé la 1.0 ?</h2> <p>Une idée que nous avons gardé en tête depuis le début de paged.js était que, tôt ou tard, les navigateurs allaient implémenter les fonctionnalités que nous utilisons si bien qu’à la fin, nous pourrions nous séparer de paged.js pour de bon. Mais ce que nous avons réalisé en chemin, c’est que le polyfill n’est qu’un usage restreint de Paged.js qui passe à côté de sa fonctionnalité principale: la prévisualisation à l’écran de ce que donnera le document imprimé permet d’imaginer les usages futurs du CSS Print.</p> <p>Pour faire simple, paged.js va lire votre HTML et votre CSS, va trouver les fonctionnalités utilisées pour le print (<code>@page</code>, <code>.footnote</code>, etc.), et va les convertir en HTML et CSS que le navigateur va pouvoir afficher à l’écran, rendant possible l’usage de l’inspecteur, meilleur ami de tout bon développeur web, pour imprimer la page en utilisant la fonction <code>save as PDF</code> du module d’impression. Dès lors, le navigateur n’imprime plus seulement la feuille de style pour le print, mais aussi ce que l’utilisateur voit dans sa fenêtre. Plus vraiment un <em>polyfill</em> mais un nouvel outil.</p> <p>La deuxième chose importante date de fin 2024, quand l’équipe derrière Chrome décide d’augmenter la voilure sur l’implémentation des features de print, <a href="https://developer.chrome.com/blog/new-in-chrome-131">en commençant avec les <code>margin-boxes</code></a>. Bonne nouvelle, CSSPrint avance, autre bonne nouvelle, mais plus technique, paged.js doit évoluer.</p> <p>Si l’on transforme paged.js pour suivre les mises à jour de chromium, alors paged.js devra tellement changer que les autres navigateurs risqueraient d’être abandonné. Même si chromium a une petite longueur d’avance sur quelque fonctionnalité que nous utilisons déjà (en particulier les veuves et les orphelines, ou la possibilité d’imprimer d’autres formats que les standards), nous continuons de penser que chaque navigateur est une option solide pour imprimer.</p> <p>Alors il faut changer la façon dont paged.js fonctionne pour être plus stable avec plus de moteur de rendu, et comme il va y avoir un nombre de changement important, passer à paged.js 2.0 nous semble être la meilleure solution.</p> <h2 id="paged.js-neue" tabindex="-1"><em>Paged.js neue</em></h2> <p>D’abord, les bonnes nouvelles.</p> <p>NLNet, par le biais de NGI 0 accompagne cette transformation de paged.js sur plusieurs projets.</p> <p>Le premier, <a href="https://nlnet.nl/project/CSS-Print/">Pushing forward for CSS Print</a> est une mission partagée entre l’équipe de WeasyPrint (les fantastiques Lucie et Guillaume) et Julie Blanc et Julien Taquet (moi-même), contributeurs de Paged.js. Ce projet finance l’écriture de spécifications pour le CSS Print pour aller plus loin que ce que nous pouvons faire aujourd’hui. La pemière de ces spécifications est la continuité du travail que nous avons commencé sur les notes. La spécification est en cours de discussion et va intégrer les conversations avec les W3C (vous pouvez la lire et la commenter ici : <a href="https://pagedjs.org/posts/fr/le-prochain-chapitre-de-paged.js/">https://css-print-lab.github.io/specs/notes-in-css-print/</a>).</p> <p>NlNet finance aussi un second projet, autour de la mise à jour de paged.js vers le 2.0. Parmi les changements qui arrivent on trouve le remplacement de cssTree par CSSOM, l’utilisation de web-components pour la partie dev, sortir le chunker de paged.js pour en faire une dépendance et permettre l’utilisations de plusiers breakTokens. Nous reviendrons là-dessus plus en détail dans les semaines qui arrivent avec un calendrier plus clair. Le financement ne peux durer qu’un an, ça donne une petite idée de la vitesse avec laquelle nous devons avancer.</p> <h3 id="la-nouvelle-%C3%A9quipe." tabindex="-1">La nouvelle équipe.</h3> <p>Depuis que Fred a intégré Mozilla à temps plein, le temps qu’il peut fournir à paged.js s’est sensiblement réduit. Nous avons décidé de lui alléger un peu les épaules en transformant un peu l’équipe autour de paged.js</p> <p>Le premier changement est l’arrivée de Gijs de Heij dans la <em>core team</em>. Gijs est un designer/developer, membre du collectif Open Source Publishing et manipule paged.js depuis suffisament longtemps pour savoir ce qui marche et ce qui va poser problème :)</p> <p>Le second changement est mon implication dans le code de paged.js. Jusqu’à présent, il s’agissait d’accompagner Fred et de tester les changements pour en rendre compte à la communauté ou proposer des plugins. Je serai beaucoup plus partie prenante dans la mise à jour du code, l’implémentation de features et l’écriture de spécifications, en plus de m’assurer que tout le monde soit ravi, que les frustrations soient réduites et que les contributeurs se sentent à l’aise.</p> <p>Sur le reste de l’équipe, Fred est toujours là, mais son temps sera forcément moindre, et si Julie ne fait plus partie officiellement de l’équipe depuis qu’elle a commencé à écrire sa thèse (dont le sujet ne peux être plus dans le mille: <a href="http://phd.julie-blanc.fr/"> “Composer avec les technologies du web ” </a>, et qu’elle a soutenu avec la plus jolie des réussites), elle n’est jamais vraiment loin de l’équipe, ni des questions qui nous concernent.</p> <p>Coko a été un super espace dans lequel dévlopper paged.js et nous ne serions pas là où on en est sans le temps, l’énergie, la confiance et la générosité d’Adam Hyde, et si Coko ne participe plus au financement de paged.js, Adam n’est jamais loin pour nous aider.</p> <h2 id="%C3%A0-propos-du-futur-de-paged.js" tabindex="-1">À propos du futur de paged.js</h2> <p>Ce poste de blog est déjà trop long, alors je ne vais pas vous prendre plus de temps, mais je dois dire en quelques mots:</p> <ul> <li>Paged.js a un compte <a href="https://fosstodon.org/@pagedjs">mastodon</a> :)</li> <li>Le code de paged.js et son site internet sont maintenant hébergés sur Github (<a href="https://github.com/pagedjs/">https://github.com/pagedjs/</a>), et nous sommes en train de rapatrier ce qui traîne sur des repos ici et là sur les différents serveurs git que nous avons pu utiliser.</li> <li>Nous sommes joignables par mail <a href="mailto:[email protected]">[email protected]</a></li> <li>Pagedjs a maintenant un channel Matrix pour discuter du futur du projet <a href="https://matrix.to/#/#pagedjs:matrix.org">https://matrix.to/#/#pagedjs:matrix.org</a></li> <li>Le site de paged.js a subi la mise à jour du fantasique <a href="https://11ty.dev">Eleventy</a> et permet donc l’internationalisation de tous ses contenus. Sérieusement je crois pas qu’il y ait meilleur générateur de site statique.</li> </ul> <p>Nous avons pas mal de choses dans les cartons, en particulier sur la partie réécriture de la documentation (de développement ET pour les utilisateurs) avec l’espoir de trouver la bonne solution pour que, si vous souhaitiez participer à son élaboration, nous puissions vous accueuillir du mieux possible.</p> <p>On se retrouve très vite.</p> <p class="signature"> julientaq </p> So long @media screen! 2022-11-11T00:00:00Z https://pagedjs.org/posts/en/so-long-@media-screen!/ <p>Hey folks.</p> <p>Yesterday night, our amazing Fred Chasen jumped the gun and pushed the 0.4.0 to<br> npm, making it the base version for any of you who use npm without version<br> control, or simply call from the unpkg cdn (or any other cdn).</p> <p>That means that if you opened your previous file without knowing what would<br> happen, you must have had a bit of a scary moment. Don’t worry too much,<br> the breaking changes were not about how paged.js works, but more on how Paged.js<br> previews things on screen.</p> <h2 id="i-want-to-go-back-to-have-a-preview-on-screen!" tabindex="-1">I want to go back to have a preview on screen!</h2> <p>Yep! Absolutely, it’s (one of) the great features of Paged.js, and we have a<br> couple of solutions for you.</p> <p>We explained it last time (<a href="https://pagedjs.org/posts/paged-break-the-long-overdue-update/">you can read the post<br> here</a>, but we<br> moved forward to follow the standards for the media queries. So, from now on,<br> pagedjs will ignore any rule that should not apply to a media screen. <code>@media screen</code> being the most useful example.</p> <p>The most standard change, for all of you, is the preview on screen: if you want<br> to use the <code>interface.css</code> we’re making, you can simply update and use the<br> <a href="https://gitlab.coko.foundation/pagedjs/interface-polyfill/blob/master/interface.css">https://gitlab.coko.foundation/pagedjs/interface-polyfill/blob/master/interface.css</a><br> for version 0.4.</p> <p>Note that if you have some css for the screen that you want to force pass to the<br> browser (for example to allow an UI around paged.js) then you can use the<br> pagedjs-ignore property in the html <code>&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;screen.css&quot; pagedjs-ignore&gt;</code> or in the css : <code>@media screen, pagedjs-ignore { .pagedjs_pages {margin-top: 20em} }</code></p> <p>Again, the previous post will tell you all about it. The good thing is that the<br> styles for the screen and the paper will stop hurting each other.</p> <h2 id="enough-with-breaking-changes%2C-we-want-features!" tabindex="-1">Enough with breaking changes, we want features!</h2> <p>And features you’ll get! Here are the release notes from the merge requests,<br> explained.</p> <h3 id="you-can-now-have-multiple-nested-named-pages%3A" tabindex="-1">You can now have multiple nested named pages:</h3> <p>Until now, you could only have one level of named page. This will fix that by<br> allowing nested named pages. For example, if this is your html</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preamble<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>This is a preamble.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre> <p>and this is your css</p> <pre class="language-css"><code class="language-css"><span class="token selector">.content</span> <span class="token punctuation">{</span><br> <span class="token property">page</span><span class="token punctuation">:</span> contentpage<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.preamble</span> <span class="token punctuation">{</span><br> <span class="token property">page</span><span class="token punctuation">:</span> preamble<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br></code></pre> <p>then the Preamble will be on its own page!</p> <h3 id="we-have-an-index-for-all-the-tests-we-have-in-pagedjs-(we-call%E2%80%99em-specs)" tabindex="-1">We have an index for all the tests we have in pagedjs (we call’em specs)</h3> <p>An image is better than a long talk right? So this is what we support.</p> <p><img src="https://gitlab.coko.foundation/pagedjs/pagedjs/uploads/9eca40bdccceabcc39f8e17105a3a834/Screen_Shot_2022-07-13_at_12.57.16_PM.png" alt="An image showing the specs that pagedsjs supports as specs we can test"></p> <p>Ok, so no, the image is not always better, especially as it’s an inaccessible<br> way to show information. So if you want to see what we support, you may want to<br> go there too: <a href="https://pagedjs.org/documentation/cheatsheet/">https://pagedjs.org/documentation/cheatsheet/</a> It’s needs a bit of<br> an update so feel free to open an issue and help us writing down the most<br> accurate feature list we can have. Please be in touch at<br> <a href="https://mattermost.coko.foundation">https://mattermost.coko.foundation</a></p> <h3 id="tables-improvement." tabindex="-1">Tables improvement.</h3> <p>Paged.js used to cut table at the first block of text overlapped the page height,<br> and this caused a column shifting beteen pages. While this was very fun to look<br> at, it was a real pain for people who worked with tables. So this is now a bit<br> better.</p> <p>Fred also fixed an issue where multiline content would break tables after a<br> page break.</p> <p>Tables are still problematic when they get long and overly complex but<br> we’ll get there eventually.</p> <h3 id="there-is-a-new-hook-in-town." tabindex="-1">There is a new hook in town.</h3> <p>Say hello to <code>finalizePage</code>. This hook runs just before the page is considered<br> rendered, after page layout is completed. When paged.js is done with the<br> <code>afterPageLayout</code> if run <code>finalizePage</code>. This allow us to manage any changes<br> that occurred in layout or when generated content was added.</p> <h3 id="looping-is-gone-(but-being-a-loop%2C-it-may-be-back)" tabindex="-1">Looping is gone (but being a loop, it may be back)</h3> <p>A looping in Paged.js world is when a code tries to do something, can’t do it and<br> tries again. and again. and again. The best example we have of that is when you<br> try to add an image on the page and there is not enough room for it. Paged.js<br> will create a new page, try to put the image on the page, and again, and<br> again, and starting to go into that infinite loop that never end.</p> <p>From now on, Paged.js 0.4 will gracefully stop when that happens.</p> <h3 id="one-but-not-least" tabindex="-1">One but not least</h3> <p>You can now reuse attributes from your element as information for your running<br> headers:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>funny-p<span class="token punctuation">"</span></span> <span class="token attr-name">data-fun</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>total<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>this is so nice<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre> <p>With that css :</p> <pre class="language-css"><code class="language-css"><br><span class="token selector">#funny-p</span> <span class="token punctuation">{</span><br> <span class="token property">string-set</span><span class="token punctuation">:</span> alphabet <span class="token function">attr</span><span class="token punctuation">(</span>data-fun<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span></code></pre> <p>will allows you to reuse the attribute as part of your generated content:</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br> <span class="token atrule"><span class="token rule">@bottom-center</span></span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">string</span><span class="token punctuation">(</span>alphabet<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>this will put in the margin bottom of the page the word <code>total</code>, since it’s the<br> value of the <code>data-fun</code> attribute</p> <p>Better, you can now have multiple string-set, if they are separated with<br> commas:</p> <pre class="language-css"><code class="language-css"><br><span class="token selector">h1</span> <span class="token punctuation">{</span><br> <span class="token property">string-set</span><span class="token punctuation">:</span> titletext <span class="token function">content</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span> <span class="token punctuation">,</span> datafun <span class="token function">attr</span><span class="token punctuation">(</span>data-fun<span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre> <p>That’s all folks!</p> <p>We’ll be back soon with some nice example of Paged.js!</p> <p>Take care</p> Paged Break, the long overdue update 2022-07-10T00:00:00Z https://pagedjs.org/posts/en/paged-break-the-long-overdue-update/ <p>It’s been a while, hasn’t it?</p> <p>That’s how it feels for us. Not that we weren’t around working, quite the opposite to be honest, but it wasn’t very visible outside of the <a href="https://mattermost.coko.foundation">Coko chat</a> (You should join if you’re interested in the future of Paged.js as we try more and more to discuss things in the open out there). We also try to offer some news on <a href="https://twitter.com/paged_js">Twitter</a>, so make sure to follow if you want some last-minute news, or if you want to ask some questions a little bit.</p> <p>Still, it feels nice to fill those pages after a year of being silent so let’s try to catch up to what happened as we’ve been a tiny bit busy.</p> <p>Before we get into that, we had to move our repo from the GitLab we had at <a href="http://pagedmedia.org">pagedmedia.org</a> to <a href="http://localhost:8080/posts/paged-break-the-long-overdue-update/">https://gitlab.coko.foundation</a>. Because Paged.js is maintained by the <a href="https://coko.foundation">Coko Foundation</a> and also because we got hit quite hard by a crazy spam that literally killed the server again and again. We’re now in a much better space as the nice folks of <a href="https://cloud68.co">cloud68.co</a> are now in charge of making our life easier, and they’re quite good at it. We managed to save the important repos and all the comments and conversations, thanks to Boris.</p> <p>Ok, back to Paged.js</p> <p>Between June last year and this month of July, we’ve been through a lot of small changes, going from 0.2.0 to 0.4.1 beta (we do have beta now!)</p> <p>Before explaining the changes, a small shout-out to our friendly users who came up with fixes. So thanks to Anthony Libotte, Guillaume Grossetie, Thomas Parisot, Angela Liu to name a few (along with the amazing work from Fred Chasen).</p> <p>We won’t spend too much time on the small fixes as they’re mostly updates to preexising features, including, better support for footnotes, a new div to be able to center things vertically, and those kinds of things. The release note for each merge request tells more than what I could write here.</p> <p>But then, here are the breaking changes.</p> <h2 id="goodbye-web2print%2C-hello-web%2Bprint" tabindex="-1">Goodbye web2print, hello web+print</h2> <p>A reminder: Paged.js is a polyfill, a Javascript library that does what the browser should be doing by itself. That means that what you do with Paged.js today needs to be what you will be able to do in Chromium, Firefox, Edge, Vivaldi, etc in future -- one day, the browsers will have implemented the print feature and when that happens, we won’t need Paged.js anymore</p> <p>To be a working polyfill, Paged.js needs to work exactly like a browser.</p> <p>In a browser, when we set @media queries, we can define styles for a specific environment. We know that well because that’s how responsive design works: you define what happens when the usable surface is smaller than 800px @media (max-width: 800px) or when night mode is wanted @media (prefers-color-scheme: dark) or simply when you want to print something with @media print.</p> <p>If you don’t set any query, then your CSS will be used in all situations.</p> <p>So a simple example: we have some <code>&lt;h1&gt;</code> and we want them to have a font-size of 2em in all situations, but we want them red on screen, black on paper. This is how it will be set.</p> <pre class="language-css"><code class="language-css"><span class="token comment">/* shared for all the context */</span> <br><span class="token selector">h1</span> <span class="token punctuation">{</span> <br> <span class="token property">font-size</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <br><span class="token punctuation">}</span> <br> <br><span class="token comment">/* only for screen */</span> <br><span class="token atrule"><span class="token rule">@media</span> screen</span> <span class="token punctuation">{</span> <br> <span class="token selector">h1</span> <span class="token punctuation">{</span> <br> <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <br> <span class="token punctuation">}</span> <br><span class="token punctuation">}</span> <br> <br><span class="token comment">/* only for print */</span> <br><span class="token atrule"><span class="token rule">@media</span> print</span> <span class="token punctuation">{</span> <br> <span class="token selector">h1</span> <span class="token punctuation">{</span> <br> <span class="token property">color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span> <br> <span class="token punctuation">}</span> <br><span class="token punctuation">}</span></code></pre> <p>Until now, you needed to have a custom stylesheet for pagedjs to handle what happens in print and on screen. If there were some styles defined for the screen in the stylesheet, they were also rendered in the preview.</p> <p>In the example above, it takes the latest value defined in the CSS cascade: the h1 would be black on screen and on paper.</p> <p>That’s the result of rendering the print preview on screen, creating the perfect paradox where eveything is used. Paged.js tricked the browser to show you the styles from the CSS for print, in a screen context, because we preview those pages, on a screen.</p> <p>Now, with this new feature, Paged.js will hide what’s for the screen and show what will be printed. Starting with version 0.4.1, Paged.js will stop parsing any css that is inside a @media screen media query. In other words:</p> <pre class="language-css"><code class="language-css"><span class="token comment">/* This will be completely remove from the page when you run Paged.js */</span> <br><span class="token atrule"><span class="token rule">@media</span> screen</span> <span class="token punctuation">{</span> <br> <span class="token selector">p</span> <span class="token punctuation">{</span> <br> <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <br> <span class="token punctuation">}</span> <br><span class="token punctuation">}</span> <br> <br><span class="token comment">/* this will be used by Paged.js */</span> <br><span class="token atrule"><span class="token rule">@media</span> print</span> <span class="token punctuation">{</span> <br> <span class="token selector">p</span> <span class="token punctuation">{</span> <br> <span class="token property">color</span><span class="token punctuation">:</span> purple<span class="token punctuation">;</span> <br> <span class="token punctuation">}</span> <br><span class="token punctuation">}</span> <br> <br><span class="token comment">/* this will be used by Paged.js as it an equivalent of @media all */</span> <br><span class="token selector">p</span> <span class="token punctuation">{</span> <br> <span class="token property">color</span><span class="token punctuation">:</span> purple<span class="token punctuation">;</span> <br><span class="token punctuation">}</span></code></pre> <p>But as we’re moving toward html AND print, we needed to change Paged.js a bit. In the previous <a href="https://pagedjs.org/posts/2020-04-15-starterkits-for-pagedjs/">post from Julie</a>, she showed how we could create a designer interface around the paged.js preview feature: show baseline, show margin boxes, etc. To make that work, she added content as a hook: when paged.js was done, it would show the toolbar, making it hard to work with (and absolutely not standard). This update will change that.</p> <p>So now, if you want to use the polyfill and have have elements just for the screen preview, you can use one of the following ways:</p> <p>Put all the interface rules in a seperate stylesheet that has a media=&quot;screen&quot; attribute, which won’t be parsed by the polyfill and only applied to screen media:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>screen.css<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>screen<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre> <p>Or add a media=&quot;screen&quot; attribute to any style tag to apply those rules to screen media and be ignored by Pagedjs:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>screen<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"> <br> <span class="token selector">p</span> <span class="token punctuation">{</span> <br> <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <br> <span class="token punctuation">}</span> <br></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span></code></pre> <p>Additionally, you can tell Paged.js to ignore <em>any</em> CSS you don’t want parsed with the pagedjs-ignore attribute:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span> <span class="token attr-name">pagedjs-ignore</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">add some inline styles</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span> <br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>screen.css<span class="token punctuation">"</span></span> <span class="token attr-name">pagedjs-ignore</span><span class="token punctuation">></span></span></code></pre> <p>This way, pagedjs will pass the stylesheet as it is, and will not update the styles. One important note: if you are ignoring screen styles, you want to make sure that you’re writing in a media screen to avoid the styles being mixed up on export.</p> <p>Finally, in a parsed CSS file, adding <code>pagedjs-ignore</code> will skip a media block, passing it as it is to the browser. This is pretty useful to define how the page will look in the browser:</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> screen<span class="token punctuation">,</span> pagedjs-ignore</span> <span class="token punctuation">{</span> <br> <span class="token selector">.pagedjs_pages</span> <span class="token punctuation">{</span><span class="token property">margin-top</span><span class="token punctuation">:</span> 20em<span class="token punctuation">}</span> <br><span class="token punctuation">}</span> <br> <br><span class="token atrule"><span class="token rule">@media</span> pagedjs-ignore</span> <span class="token punctuation">{</span> <br> // block to pass <br><span class="token punctuation">}</span></code></pre> <p>One fair warning, this is a bit outside of the standard, it’s a usable workaround that we’ll support by default, but pagedjs-ignore has no intention of being a standard in the future. But it’s a way for you to build the tool you need around real media queries support.</p> <p>You can test it already if you’re using Paged.js 0.4.0-beta.1, using the interface.css polyfill: <a href="https://gitlab.coko.foundation/pagedjs/interface-polyfill">https://gitlab.coko.foundation/pagedjs/interface-polyfill</a></p> <p>We’ll let that work as a beta for a month before making a proper release.</p> <p>The simplest way to use it is to get the file from unpkg cdn: <a href="https://unpkg.com/browse/[email protected]/dist/">https://unpkg.com/browse/[email protected]/dist/</a> and see how things work for you.</p> <p>If you find any issues, or anything, feel free to open an issue on our GitLab, or contact us on the <a href="https://mattermost.coko.foundation">Mattermost</a> (again, the best way to get in touch with us.)</p> <p>We’ll be back soon with some other updates, as Paged.js CLI also got pimped up! if you want to test the CLI with the aforementioned changes to Paged.js, you’ll find the files here: <a href="https://unpkg.com/browse/[email protected]/">https://unpkg.com/browse/[email protected]/</a></p> <p>One last thing, 27-28 October 2022 in San Francisco will see the first <em>Page Break Conf</em> which has been organized by some great folks of our community. We’ll be back to talk a bit more about it soonish, so don’t forget to save the date!</p> <p>Have a nice printing!</p> A collection of starter kits for Paged.js 2022-04-15T00:00:00Z https://pagedjs.org/posts/en/a-collection-of-starter-kits-for-paged.js/ <p>We’ve done a lot of work to bring new users to paged.js and as i’m on my way to a new workshop with graphic design students, I thought that it would be a good time to share a little bit more about the different <a href="https://gitlab.coko.foundation/pagedjs/starter-kits">starter kits</a> I've build around Paged.js since a few years to help anyone to get started.<br> And since not everyone has the same needs, it will be four stater kits instead of one.</p> <p>Depending on your needs, you can start from these ready-made folders that contain Paged.js, some CSS reset code, a bit of interfaces and sometimes JavaScript features to help your work. Choose the right one !</p> <h2 id="the-spread-book-template%3A-the-lightest-starter-kit" tabindex="-1">The spread book template: the lightest starter-kit</h2> <p>This is the simplest template, which uses the polyfill in an HTML page. The folder is already structured for you:</p> <ul> <li>An HTML file where to add the structured content of your book, the file contains the links to all other files and elements;</li> <li>A CSS file that help you to see your book in spread and where you can add the visualization of a baseline (Be careful, this visualization in spread and the baseline is only for the screen. When rendering the PDF, it will be page by page again.)</li> <li>A <a href="https://github.com/necolas/normalize.css">CSS reset file</a> to normalize the style of some elements;</li> <li>The folder for your assets: a <code>fonts</code>, an <code>images</code> and a <code>scripts</code> folder where you can add your custom scripts with a pre-coded <a href="https://pagedjs.org/documentation/10-handlers-hooks-and-custom-javascript/">handler</a>;</li> <li>And, of course, the latest version of Paged.js.</li> </ul> <p>This starter-kit exist in two version: the <a href="https://gitlab.coko.foundation/pagedjs/starter-kits/book-spread_polyfill">polyfill version</a> and the <a href="https://gitlab.coko.foundation/pagedjs/starter-kits/book-spread_esm">esm module version</a>. The difference is the way Paged.js is called on the web page. The esm version is more flexible if you want to add your custom scripts to Paged.js or integrate it with other tools.</p> <p>The polyfill version contains in addition a little helpful script developed by the great Nicolas Taffin, the <a href="https://gitlab.com/nicolastaf/pagedjs-reload-in-place">reload-in-place script</a>: “On reload, it will make the web browser scroll to the place it was before reload.”</p> <p>You can easy add it this template in an existing site, in a print folder for example. This will allow you to access a special page to print a part of your site. All the HTML content of your site must however be rewritten in this HTML page.</p> <h2 id="the-advanced-interface-template%3A-to-facilitate-your-design-process" tabindex="-1">The advanced interface template: to facilitate your design process</h2> <p>This advanced <a href="https://gitlab.coko.foundation/pagedjs/starter-kits/book_avanced-interface">starter-kit</a> contains a little interface and some features to help you during your design process. It's a template that I developed during workshops for graphic design students not used to code but which can also be used for the production of books on a daily basis. All the element of the previous “spread book template“ are also in this start-kit. I also added different features that can be used with buttons always present on the web page:</p> <ul> <li>display of the baseline with modification of its values,</li> <li>display of margin boxes,</li> <li>“visualization” mode where the cut lines are hidden,</li> <li>print button</li> <li>And number of generated pages displayed.</li> </ul> <p><img src="https://pagedjs.org/images/22-04-advanced-interface.png" alt=""></p> <h2 id="the-%E2%80%9Cprint-a-webpage%E2%80%9D-template%3A-a-responsive-web-page-that-can-be-printed" tabindex="-1">The “print-a-webpage” template: a responsive web page that can be printed</h2> <p>The last start-kit I propose is the <a href="https://gitlab.coko.foundation/pagedjs/starter-kits/print-a-webpage">“print-a-webpage” template</a>. It offers a double view of a web page: the classic web page for the responsive screen display and a paginated display for printing. Both displays are made from the same HTML content but the CSS for each version are separated. Buttons on the side of the web page allow you to switch from one version to the other or to print.</p> <p>In the printed version, all the element of the previous “spread book template“ are also in this start-kit, except the reload-in-place script.</p> <p><img src="https://pagedjs.org/images/22-04-print-a-webpage.png" alt=""></p> <h2 id="don't-forget-your-local-server" tabindex="-1">Don't forget your local server</h2> <p>Before your start, just a reminder: you need to use a local server to work on your project. Paged.js needs it to make links from one file to another and in particular to read yourCSS files. Today, all the most used text editors have extensions to launch a local server (<a href="https://www.youtube.com/watch?v=FeR_eMXzNcY">Visual Studio, Atom</a>, <a href="https://www.youtube.com/watch?v=oqD5C77Tk3I">Sublime Text</a>, <a href="https://www.youtube.com/watch?v=f35_n9NFXSw">Atom</a>).</p> <p>If you haven't done it yet, you just have to install one of these extensions and launch the local server from your project. Please note that the entire folder of your project must be open in your editor for the local server to work properly.</p> <p>Most of the errors and difficulties come from the fact that the local server is not turned on, so I advise you to be particularly vigilant on this point.</p> <p>You are now ready to get started with Paged.js! We would be very happy to see your productions, so jump on the <a href="https://mattermost.coko.foundation/">Coko Mattermost</a> to say hello (~pagedjs channel) or contact us on <a href="https://twitter.com/paged_js">twitter</a>.</p> Uke and inks 2021-06-18T00:00:00Z https://pagedjs.org/posts/en/uke-and-inks/ <h2 id="editoria%2C-the-book-production-center" tabindex="-1">Editoria, the Book Production Center</h2> <p>Editoria is a platform to collaboratively produce books, offering spaces for writers, editors, designers, etc. at the same time the content is being added.</p> <p>We've been talking Editoria quite a lot in these pages. Firstly because Paged.js was implemented in Editoria before any other tool, after years of trying out other tools to make books out of HTML.</p> <p>Editoria has been used for quite a while by Book Sprints and other friendly folks. It's a pretty amazing tool for creating books collaboratively by a team. But one of the limitations from the designer's perspective was that we were stuck with what CSS allowed us to do. It took quite a while to figure out the best option to have custom javascript hooks without compromising the security of the whole platform.</p> <p>Well, that solution exists now:)</p> <p>To show what you can do with Editoria nowadays, I have produced a small demo book, with some paged.js hooks that I explain in this post.</p> <p>Before jumping into hooks, let's briefly explain how paged.js does what it does.</p> <h3 id="paged.js%3A-hooks-and-order" tabindex="-1">Paged.js: hooks and order</h3> <p>Fred Chasen made paged.js around a clever idea: instead of defining the order of events that paged.js needed, he defined the moments where you would need to do something on the content, and set those as hooks to which you can bind your scripts.</p> <p>All the modules use those entry points to do different things at different moments.</p> <ol> <li> <p>when it's about to parse the HTML, CSS and JS.</p> </li> <li> <p>when all the content has been parsed.</p> </li> <li> <p>when you create a new page</p> </li> <li> <p>when you put one element on the page</p> </li> <li> <p>when the page is filled and there is no more space left on the page</p> </li> <li> <p>when you define the exact location your content is split</p> </li> <li> <p>when you finish the layout of the page (go back to 3)</p> </li> <li> <p>when you zend the signal that all pages are generated if there is no<br> content left.</p> </li> </ol> <p>You can see all the existing hooks <a href="https://www.pagedjs.org/documentation/11-hooks/#some-informations-about-the-hooks">on this page</a> if you want to go deeper.</p> <p>For example, let's look at how a <code>break-before: left</code> is defined.</p> <ol> <li>Before the HTML, CSS and JS of the document is parsed.</li> </ol> <p><em>check if any element has a <code>break-before</code> property and if it’s value is <code>left</code>, add a <code>data-break-before: left</code> attribute to it.</em></p> <ol start="4"> <li>when you lay out one element on the page</li> </ol> <p><em>if that element has a <code>data-break-before: left</code> attribute, stop adding elements to that page and jump to 6. Then, if it’s a right page create an <code>blank</code> page and resume adding content on the following page, else (if it’s a left page), resume adding the content.</em></p> <p>As you can see, the algorithm is crystal clear, and when the browser handles features, we'll be able to remove those that become useless over time.</p> <p>Let's start strumming our <s>ukulele</s> keyboard and make some code. :)</p> <h2 id="where-the-humuhumunukunukuapuaa-goes-swimming-by" tabindex="-1">Where the humuhumunukunukuapuaa goes swimming by</h2> <p>So let's jump in, script by script and see what happens and how things work.</p> <p>Here is the link to the <a href="https://demo.flaxjs.net/output/uke.pdf">pdf</a> and to the <a href="https://gitlab.coko.foundation/pagedjs/pagedjs-templates/ukulele-demo">repo</a> if you want to have a proper look at all those files :D).</p> <p>We’re setting up a place to display the open source templates we’re making, so stay tuned to know more about it.</p> <h3 id="changes-in-the-dom" tabindex="-1">Changes in the DOM</h3> <p>Wax, the word processor that fuels Editoria, treats the content as a<br> flat flow of elements. You can define the type of block from a list of<br> styles (including custom styles for both inline and block level<br> elements). The output of that is a nicely set HTML with <code>paragraph</code> with<br> different classes, <code>header</code>, <code>em</code>, and all the other sweets the HTML has to<br> offer.</p> <p>If all is so great, why would we change the DOM?</p> <p>For multiple reasons:</p> <ol> <li> <p>You may want to bring elements together (for example, when you have<br> two figures that belong together and for which you want to have a<br> specific layout), or when you want to nest stuff together, something<br> that your editor may not offer.</p> </li> <li> <p>To redo something the browsers used to offer (nope, not the CSS<br> regions, not this time :D) such as the unknown display:<br> <a href="https://css-tricks.com/run-in/">run-in</a> which allowed us to<br> push an element to the next as an inline block. This trick has been<br> used a lot in the world of print, and it was available for the<br> screen a long time ago. But it didn't survive the test of time.</p> </li> <li> <p>You may want to create, let's say, an index. To do so, you need to<br> create links between the words and their counterparts in the index.<br> In this book, I used a custom inline class to list everything the<br> musician talked about in the first chapter to build the list in the<br> end.</p> </li> </ol> <p>My first script, the <code>contentUkulele.js</code> is happening on the <code>beforeParsed</code><br> hook (before any content data has been processed by paged.js). It's<br> removing empty elements, add id to elements that don't have ids yet,<br> recreate the <code>display: run-in</code> property. Nothing really fancy here, but it<br> let me create the DOM I want s /I can start designing the book itself.</p> <h3 id="page-float%3F-are-you-going-to-talk-about-page-float%3F" tabindex="-1">Page-float? Are you going to talk about page-float?</h3> <p>Yes.</p> <p>And no.</p> <p>Not in the way you're expecting it.</p> <p>If you want to know what a page-float is, and what it can add to our<br> layout, you should have a look at the<br> <a href="http://demos.pagedmedia.org/page-floats/">[demo]{.ul}</a> Julie Blanc<br> made. Be aware that this is not inside Paged.js (yet) but a good demo on<br> how things should work when we'll be able to follow the specs from the<br> W3C.</p> <p>Truth is, page-floats are a pretty complex thing (check Julie's article<br> <a href="https://www.pagedjs.org/page-floats/">[about page floats]{.ul}</a>). There<br> are a lot of different ways to implement page-floats, and they all come<br> with pros and cons. Until we find the universal way of making page-float<br> a thing, we can still find workarounds and ways of making it work. So<br> let's see how I did it for the ukulele book.</p> <h3 id="the-custom-property-with-its-custom-values" tabindex="-1">The custom property with its custom values</h3> <p>This image-handling.js script has only one role: find the element that<br> has that property, and depending on its value, add a specific class to<br> that element so we can target it when it's being rendered on the page.<br> To do so, I created a CSS custom property that can have different values<br> to define where the element should float.</p> <pre class="language-css"><code class="language-css"><span class="token property">--page-float</span><span class="token punctuation">:</span> same-top<span class="token punctuation">,</span> same-bottom<span class="token punctuation">,</span> next-top<span class="token punctuation">,</span> next-bottom<span class="token punctuation">,</span> same-column-top<span class="token punctuation">,</span><br> same-column-bottom<span class="token punctuation">,</span> next-column-top<span class="token punctuation">,</span> next-column-bottom<span class="token punctuation">,</span> full-page<span class="token punctuation">;</span></code></pre> <p>Some of those values/classes are not used, but are there for the day we<br> need them.</p> <h3 id="layout-time!" tabindex="-1">Layout time!</h3> <p>Then we have a float-top.js, floatNextBis.js or fullPage.js that handles<br> the moving of elements on the page when they are rendered.</p> <p>Let's check the easiest of those scripts: fullPage.js:</p> <p>First, we define the name of the class for the image full page.</p> <pre class="language-js"><code class="language-js"><span class="token keyword">const</span> classElemFullPage <span class="token operator">=</span> <span class="token string">"imgFullPage"</span><span class="token punctuation">;</span></code></pre> <p>Then, we create our hooks like this:</p> <pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">fullPage</span> <span class="token keyword">extends</span> <span class="token class-name">Paged<span class="token punctuation">.</span>Handler</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">chunker<span class="token punctuation">,</span> polisher<span class="token punctuation">,</span> caller</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">super</span><span class="token punctuation">(</span>chunker<span class="token punctuation">,</span> polisher<span class="token punctuation">,</span> caller<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>floatFullPage<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>Hooks are sharing the same constructor. That means that if you want to<br> set a variable and use it in different hooks, you need to set it in the<br> constructor. In this script, I'm creating a <code>this. floatFullPage</code> that we're going to use to find the elements that have the <code>--page-float: full-page;</code> custom property.</p> <pre class="language-js"><code class="language-js"><span class="token function">onDeclaration</span><span class="token punctuation">(</span><span class="token parameter">declaration<span class="token punctuation">,</span> dItem<span class="token punctuation">,</span> dList<span class="token punctuation">,</span> rule</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>declaration<span class="token punctuation">.</span>property <span class="token operator">==</span> <span class="token string">"--page-float"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>declaration<span class="token punctuation">.</span>value<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"full-page"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> sel <span class="token operator">=</span> csstree<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span>rule<span class="token punctuation">.</span>ruleNode<span class="token punctuation">.</span>prelude<span class="token punctuation">)</span><span class="token punctuation">;</span><br> sel <span class="token operator">=</span> sel<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'[data-id="'</span><span class="token punctuation">,</span> <span class="token string">"#"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> sel <span class="token operator">=</span> sel<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'"]'</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>floatFullPage <span class="token operator">=</span> sel<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span></code></pre> <p><code>onDeclaration</code> is a hook that happens every time a declaration is found.</p> <p>When that happens, we check if the declaration property is <code>--page-float</code> and if the value is <code>full-page</code>. If that's the case, we get the value from of the selector (<code>sel</code>) using csstree. And we push that value to the <code>this.floatFullPage</code> array.</p> <p>Then, when the content is parsed, we use the selectors from <code>this.floatFullPage</code> to add the <code>fullpage</code> class</p> <pre class="language-js"><code class="language-js"><span class="token function">afterParsed</span><span class="token punctuation">(</span><span class="token parameter">content</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>floatFullPage<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>floatFullPage<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">elNBlist</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> content<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span>elNBlist<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">el</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> el<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"imgFullPage"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span></code></pre> <p>Then, the magic happens: every time a page is done, we run the following script:</p> <pre class="language-js"><code class="language-js"><span class="token function">afterPageLayout</span><span class="token punctuation">(</span><span class="token parameter">page</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>page<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".imgFullPage"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">;</span><br> page<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"fullPage"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> page<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".imgFullPage"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">"none"</span><span class="token punctuation">;</span><br> page<span class="token punctuation">.</span>style<span class="token punctuation">.</span>background <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">url(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>page<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".imgFullPage"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>src<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br> page<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundRepeat <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">no-repeat</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br> page<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundSize <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">cover</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br> page<br> <span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">".pagedjs_margin-content"</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">marginContent</span><span class="token punctuation">)</span> <span class="token operator">=></span> marginContent<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>When a page has a child with the class <code>full-page</code>, it will hide the image, and use the <code>src</code> attribute of the image and use it as the background for the page. We also put some css styles in there to make sure the background cover the whole page. And one last thing: we remove all the elements in the margin boxes on that page.</p> <p>The page breaks that arrive before and after are set in the css for the same element.</p> <p>And the last thing, we register the hook.</p> <pre class="language-js"><code class="language-js">Paged<span class="token punctuation">.</span><span class="token function">registerHandlers</span><span class="token punctuation">(</span>fullPage<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre> <p>We use the exact same idea for the image to top / bottom, but we're moving them as soon as they're on the page, and we use the amazing <code>shape-outside</code> property. We'll cover that deeper in the next installment of this series.</p> <p>Until then, keep practising music and book design.</p> <p>The code is accessible <a href="https://gitlab.coko.foundation/pagedjs/pagedjs-templates/ukulele-demo">here</a></p> <p>Have fun!</p> Paged.js 0.2.0 Release notes 2021-06-01T00:00:00Z https://pagedjs.org/posts/en/paged.js-0.2.0-release-notes/ <h2 id="hey-yall!-we-have-footnotes!" tabindex="-1">Hey yall! We have footnotes!</h2> <p>One day, i said on twitter that we were starting our work on the footnotes. This was the most retweeted and shared post in all the history of Paged.js. This is the most awaited feature that we’re really proud to bring into the game.</p> <p>We’ve always been happy to help making hooks for footnotes, but they were mostly hacks, and would come with their share of unknown behavior, they wouldn’t be standard and would break everything on a regular basis. Not the best of the world.</p> <p>Then, we wrote down some specifications about what we believe would be a <a href="https://www.pagedjs.org/posts/2020-05-13-notes-about-notes/">great addition to the footnotes</a>. This would allow footnote, marginnotes, different kind of notes, etc. This is a bit of how would be footnotes in the ideal world, so we could engage the conversation with the folks on the w3c github. I hope that we can be back on that conversation soon enough.</p> <p>But we can’t wait for the W3C to approve those specs as they would need to go through all the steps before being a real specs, thus we ended by making a simple implementation following the existing specs (<a href="https://www.w3.org/TR/css-gcpm-3/#footnotes">https://www.w3.org/TR/css-gcpm-3/#footnotes</a>), and we ended up with something we’re happy with.</p> <p>Footnotes now exists in paged.js and can be easily set up this way:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><br> This is a paragraph that contains some lorem ipsum<br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>footnote<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Fake latin<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> content<br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre> <p>i obviously named my class <code>footnote</code> but you can call that whatever you want. And better, your footnote can be anything from text to table, including images or more exotic HTML (warning though, this has been tested with text first and foremost).</p> <p>Then you need to define which elements need to be set as footnote using those properties:</p> <pre class="language-css"><code class="language-css"><span class="token comment">/* define what are the footnotes elements */</span><br><br><span class="token selector">.footnote</span> <span class="token punctuation">{</span><br> <span class="token property">float</span><span class="token punctuation">:</span> footnote<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token comment">/* define the position of the footnote on the page (only bottom is possible for now) */</span><br><br><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br> <span class="token atrule"><span class="token rule">@footnote</span></span> <span class="token punctuation">{</span><br> <span class="token property">float</span><span class="token punctuation">:</span> bottom<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>And that’s it. You can then style the footnote callout to go beyond the user agent styles</p> <p>Pay attention to the fact that there is no callout, they will be created automatically and you’ll be able to change their look with css without having to worry with the note numbering.</p> <pre class="language-css"><code class="language-css"><span class="token selector">::footnote-call</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">counter</span><span class="token punctuation">(</span>footnote<span class="token punctuation">,</span> loweralpha<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><br> <span class="token property">font-weight</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span><br> <span class="token property">font-size</span><span class="token punctuation">:</span> 3em<span class="token punctuation">;</span><br> <span class="token property">line-height</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">::footnote-marker</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">counter</span><span class="token punctuation">(</span>footnote<span class="token punctuation">,</span> loweralpha<span class="token punctuation">)</span> <span class="token string">". "</span><span class="token punctuation">;</span><br> <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><br> <span class="token property">font-weight</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span><br> <span class="token property">font-size</span><span class="token punctuation">:</span> 3em<span class="token punctuation">;</span><br> <span class="token property">line-height</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>You can check this <a href="https://codepen.io/julientaq/pen/dyvQaKy">codepen</a> to see it in action.</p> <p>To be able to manage the footnotes, Fred rewrote quite an amount of code of Paged.js. He made sure that the API didn’t change, but it doesnt mean that your previous content will work by default. Please test, and tell us if something goes wrong, we’ll be happy to support you.</p> <p>Welcome Paged.js 0.2.0! :)</p> <h2 id="release-notes" tabindex="-1">Release notes</h2> <ul> <li>Footnotes! (from @Fred)</li> <li>Fix styles order (from @Guillaume)</li> <li>White space in <code>&lt;pre&gt;</code> elements are now preserved. Hello again ascii art! (from @Guillaume)</li> <li>A lot of improvement on tables from @guillaume) (Break in table with row span are now much more elegant, columns are rebuild on page breaks, etc.)</li> <li>remove page border when no borders are specified (from @guillaume)</li> <li>@Julie wanted to print page with a lot of colors, so she added box-shadows to the crop marks</li> <li>@guillaume introduced the <code>RenderResult</code> object with more data about how pagedjs handle page breaks.</li> </ul> <h2 id="in-other-places" tabindex="-1">In other places</h2> <p>We now have a <a href="http://pagedjs.org/examples/">portfolio page</a>. Send us a message if you want to display your work here.</p> <p>One of the great thing of using the browser is to inherit all the knowledge they have: as a result, Paged.js works pretty well with content in chinese, thanks to <a href="https://twitter.com/aszx87410">huli</a>.</p> <p>C&amp;F editition are working on their new collection using Paged.js but hush, it’s a surprise.</p> <p>And Julien spent some time to build hooks for page float, automatic indexing, and other things we’ll be happy to show you soon. This <a href="https://pagedjs.org/images/exampleOUT.pdf">PDF</a> was made with <a href="https://pagedjs.org/posts/en/paged.js-0.2.0-release-notes/www.editoria.pub">Editoria</a>. Video tutorials are coming!</p> <p>Until next time!</p> A paged.js hackathon at EnsadLab 2021-03-18T10:00:02Z https://pagedjs.org/posts/en/a-paged.js-hackathon-at-ensadlab/ <p>On the 1st and 2nd of March 2021, a group graphic designers went together in Paris for a Paged.js hackathon. The goal was to bring together people who already had an experience with Pagedjs to discover how they worked, how they come to layout their content, and to think together about pushing the boundaries further. The hackathon, organised by Julie Blanc and Lucile Haute welcomed Julien Taquet, Manu Vazquez, Louis Éveillard, Sarah Garcin, Robin de Mourat and Quentin Juhel.</p> <p><img src="https://pagedjs.org/images/9J1A5482_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5333_retouch.jpg" alt=""></p> <p>Despite the context of that global pandemic, we were able to meet at EnsadLab and we got lucky to have the pleasure of spending two days together.</p> <p>The idea was to go deeply into how Paged.js works, to work on scripts to improve and extend Paged.js and to discuss what #CSSPrint change in terms of page layouts and new workflows for graphic designers.</p> <p>We started the workshop looking at projects made by the participants. During the first morning, they showed the specific improvements they had already made to Paged.js and the difficulties they encountered in the layout rendering or in the workflows with their co-workers (authors, editors, print shops, etc.). From there, we worked on different ideas that were raised along that talk.</p> <p>Generally, we have discussed and worked with <a href="https://www.pagedjs.org/documentation/11-hooks/">handlers and hooks</a>. The source code of Paged.js is organised in such a way in order to facilitate the addition of functionalities through the handlers and hooks. The hooks are a kind of specific breakpoint in the execution of the script that give the possibility to add your own script at different moments of the document pagination and rendering (for example before the css is parsed, and after, before the pagination of the document, before or after the fragmentation of a specific page, before and after the addition of elements in the page, etc.).</p> <p><img src="https://pagedjs.org/images/9J1A5203_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5476_retouch.jpg" alt=""></p> <p>The results of the workshops are not usable as working bit directly. Some of them can be adapted to your use if you are comfortable with the use of paged.js, others still require a bit of development. All the source codes are available in <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021">a dedicated repo on our gitlab instance</a>. In this article, we offer you a summary of the discussions and the work done.</p> <h2 id="documentation" tabindex="-1">Documentation</h2> <p>Sarah worked around baselines. She wrote the <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/blob/master/baseline-experiment_sarah/baseline-documentation.md">beginning of a documentation</a> about it (in French): how to uses variables to fit a baseline grid, why using pixel values and instead of pt value, how to add visual guideline, etc. She also developped some <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/baseline-experiment_sarah">scripts</a> to automatically align elements (even images) on the baseline grid with the use of <code>offsetTop</code>. She went further in the experimentation by positioning the elements randomly in the page and keeping the elements aligned on the baseline.</p> <p><img src="https://pagedjs.org/images/9J1A5322_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/baseline.png" alt=""></p> <p>Manu took advantage of the hackathon to document the <a href="https://gitlab.coko.foundation/tools/experiments">&quot;experiments&quot; repo</a> available on the gitlab. This repo contains various experimental scripts tried in the last years. Some of them are still under development and can be used for your projects with some adaptations but nobody had taken the time to document them yet. Based on his experience with BookSprints, he also works with Julie on a <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/delete-margin-content_manu">little script</a> to delete content of margin boxes when an element appears on the page.</p> <h2 id="canvas-html-for-images-and-for-drawing" tabindex="-1">Canvas HTML for images and for drawing</h2> <p>Following stories of problems with offset printers with the use of CSS mix-blend-mode on some images, Robin and Louis came with the idea of using canvas <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/blend-modes">to recreate the image and its effects</a>. Beyond CSS <code>mix-blend-mode</code>, the use of canvas for images is a real positive point that allows a better optimization of images for printing.</p> <p><img src="https://pagedjs.org/images/9J1A5636_retouch.jpg" alt=""></p> <p>Louis also worked <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/canvas_embedding-louis">with canvas</a>. He made a system to inject external javascript into canevas and drawing things or downloading API. A script can be added on the fly with the <code>data-script</code> attribute in the canvas and the size of the canvas must be given in advance to avoid overflow problems.</p> <h2 id="float-notes" tabindex="-1">Float notes</h2> <p>Robin and Julie works on an old script written 2 years earlier to create <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/notes-float">float notes</a>. The script has been improved and optimized because the old version had serious problems with the fragmentation of the text content when notes was moved into floated areas. The idea is to be able to have a first implementation of a part of the <a href="https://github.com/w3c/css-print/issues/3">draft specifications for notes</a> proposed by the Paged.js team. These are the first foundations but there is still a lot of work to be done to achieve a solid result (so be careful if you want to use the script).</p> <p><img src="https://pagedjs.org/images/9J1A5473_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/float-notes.png" alt=""></p> <h2 id="imposition" tabindex="-1">Imposition</h2> <p>Quentin, a fanzine lover, makes a lot of Paged.js workshops with students. Most of the time, they print their own productions and therefore need a way to impose the sheets after the paged.js rendering. With Julien’s help, <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/imposition_quentin_juhel">he made a script</a> to re-organize the dispositions of the pages, automaticly add pages to have a multiple of 4 and change the size of the spread after the rendering of the document. The script is only a first step and they want to develop it further to make more complex spreads (this whole idea was based on a script Julien Bidoret made).</p> <p><img src="https://pagedjs.org/images/9J1A5506_retouch.jpg" alt=""></p> <h2 id="automatic-grid-layout" tabindex="-1">Automatic grid layout</h2> <p>Louis used <a href="https://mapbox.github.io/potpack/">Potpack</a>, a “tiny and fast JavaScript library for packing boxes of varying size into a near-square container“, to distribute image elements on the page according to their number and ratio. The <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/auto_layout_images-louis">script available on the repo</a> is a good example of how automatic grid layout algorithms (for example <a href="https://masonry.desandro.com/">Masonry</a>, <a href="https://packery.metafizzy.co/">Packery</a>) can be easily added to Paged.js. The idea is to start preparing javascript modules, usable with the addition of some classes in the HTML. That could be used by people who are not developers or graphic designers who do not code.</p> <p><img src="https://pagedjs.org/images/9J1A5002_retouch.jpg" alt=""></p> <h2 id="create-a-link-between-content-and-pagination" tabindex="-1">Create a link between content and pagination</h2> <p>During the first morning, Sarah and Julie told about the time-consuming last step of the composition of books: typographic corrections and flag management. The desynchronization of writing (on the HTML source code) and rendering (in the web browser) can make the work fastidious.</p> <p><img src="https://pagedjs.org/images/paged-editor.png" alt=""></p> <p>So Louis looked for a way to create a better link between the two. <a href="https://gitlab.coko.foundation/pagedjs/hackathon-mars-2021/tree/master/paged_editor-louis">He imagined an interface</a> in the browser with, on the left, the editable content as a single flow and on the right, the paginated render in a page-by-page display. The two area are linked and clicking on an item will display it in both areas synchronously. It's also possible to modify the content on the left and have it update on the right paginated rendering. This is a very good start to imagine more advanced interfaces integrating Paged.js as a tool.</p> <p><img src="https://pagedjs.org/images/montage-1.png" alt=""></p> <p>Hackathon is a very interesting way of working to quickly come up with design ideas and see how to add them in paged.js. These two days were a success and we hope to find the opportunity to do other events.</p> <p><em>Thanks to EnsadLab for the financial and logistic support, Lucile Haute for the great help about the organization, Agathe Charrel for photos and all the participants for this two wonderful days.</em></p> <hr> <p><img src="https://pagedjs.org/images/9J1A5546_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5566_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5614_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5465_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5511_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5115_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5299_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5370_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5382_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5157_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5257_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5303_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5390_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5419_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5430_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5537_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5539_retouch.jpg" alt=""><br> <img src="https://pagedjs.org/images/9J1A5716_retouch.jpg" alt=""></p> Avoid whitespaces on pages 2020-09-21T09:58:02Z https://pagedjs.org/posts/en/avoid-whitespaces-on-pages/ <p>A long time ago, I wrote an article about <a href="https://www.pagedjs.org/page-floats/">page floats</a>. Since then, we've had a lot of feedback about these CSS features that are crucial for paginated layout. We haven't yet implemented them in paged.js – because it's difficult and we need to take the time to ponder how to do. However, we are facing a recurring and urgent request regarding a specific aspect of page floats. I'm writing today to answer it :)</p> <p>I'm sure you already know what I'm talking about. You know, this figure or this table that didn't fit at the end of your page? Because of how pagined medias works, if an element ends up at the bottom of a page but is too big to fit within the page height, the element is automatically pushed to the next page with a forced page break. This produces a gap, a white space, at the end of the previous page. It’s unsightly and, moreover, the reader might think that it means the end of a section.</p> <p>The float properties can fix this problem, just by adding <code>float: top</code> and <code> float-reference: page</code> on the problematic element. The following figure illustrates what this should look like:<br> <img src="https://pagedjs.org/images/whitespace-script.png"></p> <p>However, we can't use it today. I personally encounter this problem in some book design I make. So, based on a script made by <a href="https://gitlab.coko.foundation/julientaq">Julien</a> I share with you a little script to make floating-like elements in paged.js to avoid large chunks of whitespace at the end of pages. For this, we add a custom module to Paged.js using <a href="https://www.pagedjs.org/documentation/11-hooks/">handlers and hooks</a>.</p> <p>As you can see, the script is not very long. You just have to add it in your HTML document (after the paged.js script), add the class <code>elem-float-top</code> to the elements where you want it to apply, and watch the magic happen.</p> <pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> classElemFloat <span class="token operator">=</span> <span class="token string">"elem-float-top"</span><span class="token punctuation">;</span> <span class="token comment">// ← class of floated elements</span><br><br><span class="token keyword">class</span> <span class="token class-name">elemFloatTop</span> <span class="token keyword">extends</span> <span class="token class-name">Paged<span class="token punctuation">.</span>Handler</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">chunker<span class="token punctuation">,</span> polisher<span class="token punctuation">,</span> caller</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">super</span><span class="token punctuation">(</span>chunker<span class="token punctuation">,</span> polisher<span class="token punctuation">,</span> caller<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>floatPageEls <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>token<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">layoutNode</span><span class="token punctuation">(</span><span class="token parameter">node</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// If you find a float page element, move it in the array,</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>node<span class="token punctuation">.</span>nodeType <span class="token operator">==</span> <span class="token number">1</span> <span class="token operator">&amp;&amp;</span> node<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span>classElemFloat<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> clone <span class="token operator">=</span> node<span class="token punctuation">.</span><span class="token function">cloneNode</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>floatPageEls<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>clone<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token comment">// Remove the element from the flow by hiding it.</span><br> node<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">"none"</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">beforePageLayout</span><span class="token punctuation">(</span><span class="token parameter">page<span class="token punctuation">,</span> content<span class="token punctuation">,</span> breakToken</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// If there is an element in the floatPageEls array,</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>floatPageEls<span class="token punctuation">.</span>length <span class="token operator">>=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// Put the first element on the page.</span><br> page<span class="token punctuation">.</span>element<br> <span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".pagedjs_page_content"</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">insertAdjacentElement</span><span class="token punctuation">(</span><span class="token string">"afterbegin"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>floatPageEls<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>floatPageEls<span class="token punctuation">.</span><span class="token function">shift</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br>Paged<span class="token punctuation">.</span><span class="token function">registerHandlers</span><span class="token punctuation">(</span>elemFloatTop<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre> <p><strong>Note</strong>: It's not exactly how the float page specifications work, but it's currently the easiest way to do it with Paged.js. A real <code>float: top</code> on an element should move the element to the top of the page where it is anchored. However, this would mean that the text already rendered in the page by paged.js (which is before the element) would have to be pushed to the next page, causing the text to be split again. There is currently no simple way in paged.js to re-render the page if an element in the layout is moved. For the moment, this script is the easiest way to do it.</p> Welcome Pagedjs 0.1.42 2020-06-20T13:42:08Z https://pagedjs.org/posts/en/welcome-pagedjs-0.1.42/ <p>Hi there!</p> <p>It’s been a while since we talked, but we have used the time wisely.</p> <p>First, we were very happy to see Julie (along with <a href="https://pagedjs.org/posts/en/welcome-pagedjs-0.1.42/www.twitter.com/nt_polylogue">Nicolas Taffin</a>) and Fred in the line-up of the <a href="https://openpublishingfest.org/">Open Publishing Fest</a> talking about Paged.js. Their discussions and demos are pretty good examples of the use of Paged.js in the real world: Julie talked about her work on the <a href="https://julieblanc.gitlab.io/projects/villa-chiragan/">Villa Chiragan</a>, Nicolas focused on the ways <a href="https://cfeditions.com/public/">C&amp;F Editions</a> are using paged.js for their new collections; and Fred showed an experiment of his, on using paged.js to render epub on the screen as fixed layout. Would printing epub be something worth having in the future? :)</p> <p>Be sure to look in the <a href="https://openpublishingfest.org/archives.html">archives</a> at all the great content folks submitted to the fest.</p> <h2 id="bug-fixes-and-updates-to-paged.js" tabindex="-1">Bug fixes and updates to paged.js</h2> <h3 id="basic-support-for-correct-borders-on-the-page-!107" tabindex="-1">Basic support for correct borders on the page <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/107">!107</a></h3> <p>We now handle <code>border</code> on the page as the <a href="https://drafts.csswg.org/css-page/#page-model">specifications define it</a>. The <code>border</code> will not be set as a border for your page anymore, but will be between the page margins and padding. If you want to have a drawn border on your page, you’ll be able to use <code>box-shadow: inset</code>.</p> <h3 id="added-a-license-banner-!127" tabindex="-1">Added a license banner <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests">!127</a></h3> <p>Paged.js include the version in its header thanks to Guillaume (@mogztter),</p> <h3 id="fixes-for-reset-on-page-counter-!128-and-fixes-page-counter-!124" tabindex="-1">Fixes for reset on page counter <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/128">!128</a> and Fixes page counter <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/124">!124</a></h3> <p>You can now reset the numbering of your page and set the number it starts from using, for instance, <code>counter-reset: page 20</code>. But when Guillaume starting to look at how it was supposed to work, he ended up with a tricky situation: setting reset anywhere in the CSS doesn’t seem to be valid CSS, but at the same time, it’s how the majority of all the other tools are working. We implemented a quick fix to help authors used to this way of writing css down, but we have a more in-depth article coming. Side note, you can now set up a custom increment for the page counter.</p> <h3 id="updated-page-breaks-on-new-named-page-!126" tabindex="-1">Updated page breaks on new named page <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/126">!126</a></h3> <p>Guillaume also fixed a longtime bug, where a named page would create an empty page if it was the first page of the book.</p> <h3 id="handling-for-nth-of-type-and-following-(%2B)-selectors-!122%2C-!125" tabindex="-1">Handling for nth-of-type and following (+) selectors <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/122">!122</a>, <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/125">!125</a></h3> <p>Nellie McKesson, from the amazing <a href="https://www.hederis.com/">Hederis</a> helped all of us write better CSS by adding support for <code>+</code> and <code>nth-of-type</code> selector.</p> <h3 id="prevent-infinite-loops-when-elements-aren't-placeable-!118" tabindex="-1">Prevent infinite loops when elements aren't placeable <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/118">!118</a></h3> <p>Pagedjs used to have infinite loops when trying when an element was bigger than the page. If that happens now, it will stop the rendering on the element that doesn’t appear on the page. No more linking from CPU and RAM.</p> <blockquote> <p><strong>Breaking change</strong></p> <p>If one of your scripts used <code>breakToken</code> to move things around, make sure to test it: Paged.js now stops rendering when the <code>breakToken</code> is the same on two consecutive pages.</p> </blockquote> <h3 id="non-significant-text-handling%3A-!115" tabindex="-1">Non-significant text handling: <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/115">!115</a></h3> <p>This merge request ignores non-significant Node such as a Text node that is all whitespace, or a Comment node. It also preserves Text node that does not have any sibling such as empty (<code>&lt;p&gt; &lt;/p&gt;</code>) or Text node with a sibling (<code>Hello &lt;span&gt;world&lt;/span&gt;</code>).<br> Here, the Text node after <code>&quot;Hello&quot;</code> and before the <code>&lt;span&gt;</code> element must be preserved. In this case, the <code>textContent</code> is updated to a single space:<br> <code>Hello &lt;span&gt;world&lt;/span&gt;</code>. This fixes a couple of issues with <code>break-after: avoid</code>. For more information about how HTML handle white spaces, you can head over to <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace">MDN</a>.</p> <h3 id="add-filter-hooks-and-modules%3A-!116" tabindex="-1">Add filter hooks and modules: <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/116">!116</a></h3> <p>Add a <code>filter</code> hook that happens just before the <code>afterParsed()</code> one. It allows filtering the content rendered by paged.js. For now, those modules are enabled by default:</p> <ul> <li><code>WhiteSpaceFilter</code>: remove whitespace when possible.</li> <li><code>CommentsFilter</code>: remove all comments.</li> <li><code>ScriptsFilter</code>: remove all script elements.</li> <li><code>UndisplayedFilter</code>: Mark elements set to <code>display:none</code> as undisplayed.</li> </ul> <h3 id="allow-setting-margins-without-units%3A-%23112" tabindex="-1">Allow setting margins without units: <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/issues/112">#112</a></h3> <p><code>@page {size: 0 0}</code> is now rendered correctly.</p> <h3 id="wait-a-frame-before-handling-resize%3A-!110" tabindex="-1">Wait a frame before handling resize: <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/110">!110</a></h3> <p>Thanks a lot to Edoardo Tona (@EdoardoTona) who helped us figure out a bug in Chrome when, sometime, the pdf output is different from the screen preview (on the last part of the page) and the print PDF. By waiting 1 frame, the content is now identical.</p> <p>Many great code bug-fixes: <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/111">Nicholas Wylie fixed the ordered list numbering</a>, <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/88">Gregorio Roper, @garoper, fixed the issue when using page counter and custom counters</a>, and we <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/121">updated to Pupeteer 3</a>.</p> <p>Thanks to everyone who contributed. You’re amazing.</p> <h2 id="some-interresting-projects-using-paged.js" tabindex="-1">Some interresting projects using Paged.js</h2> <ul> <li><a href="https://twitter.com/ma_salmon/">Maëlle Salmon</a> made a proof of concept to make Paged.js work on the server on a Hugo website: <a href="https://github.com/maelle/testbook">https://github.com/maelle/testbook</a>.</li> <li>The folks at <a href="https://voting.works/">Voting Works</a> are building open-source voting systems for US elections. One of their projects, Vote by mail, uses Paged.js to generate voting ballots: “VotingWorks Vote-by-Mail makes scaling vote-by-mail operations quick and affordable”.</li> </ul> <!-- ## The question of the page counter --> <p>And that’s it for today.</p> <p>If you find any bugs, or have any questions, or want to discuss anything, feel free to join us on our chat: <a href="https://pagedjs.org/posts/en/welcome-pagedjs-0.1.42/mattermost.coko.foundation.org">mattermost.coko.foundation</a></p> Notes About Notes 2020-05-13T13:42:08Z https://pagedjs.org/posts/en/notes-about-notes/ <p>CSS is a language that evolves by adopting new specifications. To be accepted as rules and properties published by the W3C, a proposal for new features is debated, adopted or rejected by the CSS Working Group which is made of a broad community of users, company representatives, invited experts and browser developers. Turning an idea for a new feature into an actual standard is a long process of discussion and debates in which complex cases are discussed, examples of implementations are shown, and decisions are made.</p> <p>Since its third version, CSS has been divided into modules which share families of properties. Each “module” has one or more editors who coordinate community responses towards further module development. From the very first phase of writing, module discussion documents are made available to everyone interested to read them. These documents are initially known as “working drafts” and evolve towards &quot;Candidate Recommendation&quot; status as the community discusses and revises their ideas. Recently, the creation of the CSS Grid module has been a great example of the success of this process: the final module has been defined collectively, well written, and quickly implemented by the browser developers.</p> <p>However, not all CSS modules evolve at the same speed, and even though they’ve been started a long time ago, the paged media specifications still need to be implemented in browsers, which is why Paged.js exists.</p> <p>So how can we help get the page media specification process moving?</p> <h2 id="proposing-new-specifications" tabindex="-1">Proposing new specifications</h2> <p>On 13 February 2020 at XML Prague, a CSS Print Workshop took place. The workshop was chaired by Rachel Andrew and Dave Kramer, both members of the CSS working Group. Dave is also the editor of the CSS <em>Generated Content for Paged Media Module</em>. Paged.js team attended the workshop and were able to discuss with them how to make the specifications for paginated media and printing evolve more quickly. Following the workshop, the <a href="https://www.w3.org/community/cssprint/">CSS print community group</a> was launched, “a community of users of CSS print, working together to gather use cases, help with specifications, and advocate for more and better implementations”. This subgroup will strengthen the work of the CSS working Group by focusing on CSS for print and paged media.</p> <p>The work of the W3C and the CSS working Group is easily accessed on the <a href="https://github.com/w3c/csswg-drafts">dedicated repo on github</a>. During that CSS Print Workshop, Rachel Andrew <a href="https://noti.st/rachelandrew/Hy20NS/introduction-to-the-css-working-group">described the status of the CSS Working Group</a>, how it works and how to contribute (<a href="https://www.youtube.com/watch?v=Cp1QLxZLfmM">first part of the video</a>). Anyone can contribute to the specifications in multiple ways: showing use cases, contributing examples and diagrams to the specifications, writing tests or even proposing some properties.</p> <p>This new CSS print community group has decided to start participating in the specification as well. Our daily work with Paged.js has allowed us to develop a good knowledge of the existing specifications and also where they would need a new look. Cabbage Tree Labs, the house of Paged.js, is now part of the W3C, and as a first move, we want to propose specifications dedicated to the different types of notes that exist in editorial design.</p> <h2 id="types-of-notes-and-pattern" tabindex="-1">Types of notes and pattern</h2> <p>The W3C specifications only allow the creation of footnotes, but designers and editors like to make use of all kinds of notes. To name a few:</p> <ul> <li><strong>Footnotes</strong>: notes placed at the bottom of the pages</li> <li><strong>Side notes</strong>: notes related to the page content, grouped in the left or in the right of the page, alongside the text area</li> <li><strong>End notes</strong>: notes grouped together in one place at the end of a document or at the end of a section of the document</li> <li><strong>Marginal notes</strong>: notes that are placed to one side of a page or both sides at the exact vertical position of the note reference number</li> <li><strong>Column footnotes</strong>: footnotes that can be placed according to the column in which they are located</li> <li><strong>Multiple notes area</strong>: not for pages that share footnotes, margin notes, column footnote, etc.</li> </ul> <p>You can find some example of layouts with footnotes in a <a href="https://www.w3.org/XML/2015/02/footnote-examples/">dedicated W3C page</a>.</p> <p>To make use of notes easier, we would like to propose some CSS syntax which would allow all of these kinds of notes. This article is a quick tour of a proposed specification that is described in more detail in an issue on the CSS Print Community Group repo. The article explores the existing specifications and proposes some new CSS declarations for building notes for both continuous reading (screen) and paged media. This proposal is a working draft, a place to start a discussion. Do not hesitate to give your opinion directly as a comment of this article, or if you feel more comfortable, in the <a href="https://github.com/w3c/css-print/issues/3">issue</a> we've opened on CSS Print Community Group.</p> <h3 id="pattern-to-create-notes" tabindex="-1">Pattern to create notes</h3> <p>Notes always depend on another flow but there are out-of-flow elements, <em>ie.</em> it’s ancillary content that can be moved to the bottom or the side of the page or the document. A note is created when the content is moved to another specific area of the document or the page, leaving a indicator of where it was (a reference).</p> <p>All types of notes are built to a similar pattern:</p> <ol> <li>Declare that an element of a flow is a note.</li> <li>Remove the item from the flow.</li> <li>Leave a note reference indicator which points to the place the note element was moved from. This is an explicit link from a location in the document to a note element.</li> <li>Place the note element and its children in a special area with all the other notes of the page or the document, in the order of appearance in the flow.</li> <li>Create a marker before the note that matches the note reference.</li> <li>Place the note area in the page or the document using appropriate CSS layout facilities and position scheme.</li> <li>(If paged media) If the note overflows the note area, move the items to the next page in the equivalent area according to note policy.</li> </ol> <h2 id="how-to-tag-a-note-in-html-%3F" tabindex="-1">How to tag a note in HTML ?</h2> <p>The W3C doesn't provide a dedicated way to tag notes in HTML. Currently, there are two most commonly used methods of adding notes:</p> <ul> <li>A list of notes at the end of the document, with note references as link elements with <code>href</code> attributes pointing to the note using fragment URLs;</li> <li>or <code>&lt;span&gt;</code> elements directly in paragraphs to encapsulate note elements in the place where they appear. This is the method used in examples in the <a href="https://www.w3.org/TR/css-gcpm-3/#creating-footnotes">css-gcpm-3</a>.</li> </ul> <p>After some research, reflections and a closer look at some use cases and requirements, a proposal from paged.js team has been developed to allow for this need for various kinds of notes: that there should be a new HTML tag, the <code>&lt;note&gt;</code> element which will interact with appropriate CSS to handle notes of various kinds. (This choice is more fully detailed in the GitHub issue.)</p> <p>A <code>note</code> element represents a note, eg. secondary content that is related to other content in the document. It’s a self-contained node that gives the information about where a note starts and where it ends. The <code>note</code> element must be placed where the note appears in the content flow. It's the CSS mechanism proposed in this article that allows you to place the note elsewhere in the layout and to create the note call.</p> <p>The following example is a conforming HTML fragment:</p> <pre class="language-html"><code class="language-html"><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Gutenberg in 1439 was the first European to use movable type. Among his many contributions to printing are: the invention of a process for mass-producing movable type; the use of oil-based ink for printing books; <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>note</span><span class="token punctuation">></span></span>Soap, Sex, and Cigarettes: A Cultural History of American Advertising By Juliann Sivulka, page 5<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>note</span><span class="token punctuation">></span></span> adjustable molds; mechanical movable type; and the use of a wooden printing press similar to the agricultural screw presses of the period.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre> <p>This potential new HTML element is easy to use and allows a note to be always attached to the content it adds details to. This proposal is aligned to the way HTML works (a node mechanism) without adding an HTML element that would depend on another one (to create note references for example).</p> <p>Until this element exists in HTML, a <code>span</code> element will be used with a class named “note” for illustrative purposes.</p> <p>The new CSS specifications to be proposed will allow the transformation and layout of the targeted element into different types of notes. The stylesheet provides alternate ways to organize and display notes, for specific uses and for continuous and paged media alike. In addition, the specification defines the area where the notes would be gathered / relocated in CSS if needed.</p> <h2 id="layout-the-notes" tabindex="-1">Layout the notes</h2> <h3 id="footnotes-in-w3c-css-specs" tabindex="-1">Footnotes in W3C CSS specs</h3> <p>Let’s start by looking at what already exists in the W3C specifications. A part of the <a href="https://www.w3.org/TR/css-gcpm-3/#footnotes">CSS Generated Content for Paged Media Module</a> (css-gcpm-3) is dedicated to footnotes. The first section defines the terms of the footnote objects: <code>footnote element</code>, <code>footnote marker</code>, <code>footnote body</code>, <code>footnote call</code>, <code>footnote area</code> and <code>footnote rule</code>. These definitions can be applied to all types of notes. For the rest of this article, these same terms will be used without the prefix “foot” to the term footnote.</p> <p>The specification also describes how to create footnotes in a page with the following code:</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@footnote</span></span> <span class="token punctuation">{</span><br><span class="token property">float</span><span class="token punctuation">:</span> bottom<span class="token punctuation">;</span><br>/_ style of footnote area _/<br><span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token selector">span.footnote</span> <span class="token punctuation">{</span><br>/_ Display span as footnote _/<br><span class="token property">float</span><span class="token punctuation">:</span> footnote<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>This code also creates special <a href="https://www.w3.org/TR/css-gcpm-3/#footnote-counters">footnote counter</a> and special pseudo-elements for <a href="https://www.w3.org/TR/css-gcpm-3/#footnote-call">footnote calls</a> (<code>::footnote-call</code>) and <a href="https://www.w3.org/TR/css-gcpm-3/#footnote-marker">footnote markers</a> (<code>::footnote-marker</code>). The position, size and the styles of the footnote area are defined by the <code>@footnote</code> declaration. The specification does not give much indications, <a href="https://www.w3.org/TR/css-gcpm-3/#footnote-area">only a couple of paragraphs and a lot of issues and unanswered questions</a>. The advantage is that we can do many proposals without conflicting with the current specifications.</p> <p>A mechanism is needed to move the note element into specific areas of the page or the document. To do this, inspiration can be taken from a mechanism already present in the draft of the paged media specifications, the <a href="https://www.w3.org/TR/css-gcpm-3/#running-elements">running element</a>: by adding the <code>position: running()</code> declaration, an element can be removed from the flow, and reused in multiple places, perfect for the running heads of a book for example.</p> <h3 id="new-proposal-to-create-note" tabindex="-1">New proposal to create note</h3> <p>This proposal is for a new way to create and place notes, based on new values (<code>note()</code> and <code>element()</code>) for properties already in the CSS specifications (<code>position</code> and <code>content</code>). This could work for both media: paged media and screen.</p> <p>In paged media, a new <code>@note-area</code> at-rule must also be added to be able to move notes from the page to a specific place. Here is an example of how it would work:</p> <pre class="language-css"><code class="language-css"><span class="token selector">.note</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>notes<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@note-area</span></span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>notes<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>This proposal can also work for continuous media by placing the notes in a new pseudo element <code>::notearea</code> that is created at the end of the declared element (just before the pseudo element <code>::after</code>). All the notes contained in the element would be placed in this new pseudo element.</p> <pre class="language-css"><code class="language-css"><span class="token selector">.note</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>notes<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">section::note-area</span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>notes<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <h4 id="the-note()-and-element()-functions" tabindex="-1">The <code>note()</code> and <code>element()</code> functions</h4> <p>In both cases, the <code>note()</code> function declares an element as a note, removes the element from the principal flow, and makes it available to place in a page margin-box, a page note-area <code>@note-area</code> or a <code>::note-area</code> pseudo element using <code>element()</code>.</p> <p>The <code>element()</code> function already exists in <a href="https://www.w3.org/TR/css-gcpm-3/#creating-footnotes">css-gcpm-3</a>. It's usable in the <code>content</code> property of margin boxes. The proposal would see it used in the new page area <code>@note-area</code> or a <code>::note-area</code> pseudo-element.<br> To make <code>element()</code> work with <code>note()</code>, a specific behaviour needs to be added that can be declared via an optional keyword <code>all-once</code>. The value of all the assignments of the document or the page are used. ie. all the note elements are displayed in the new area where they're assigned in the same order of the flow and have only one assignment in the document or in the page (the elements are not repeated).</p> <p>The note element inherits from its original position in the document, but is not rendered there, instead a <code>::note-call</code> pseudo-element is created and inserted in the original position of the note. When the note element is displayed in this new area, a <code>::note-marker</code> corresponding to the<code>::note-call</code> is created before the note body.</p> <h3 id="using-css-layout-possibilities-with-the-notes-area" tabindex="-1">Using CSS layout possibilities with the notes area</h3> <p>The <code>@note-area</code> at-rule creates special <a href="http://dev.w3.org/csswg/css-page/#page-area">page areas</a> that can be used to display notes elements via the <code>element()</code> function. The other central idea of this proposal is that any of the CSS layout facilities can be used to create, position and size note areas: float, absolute positioning, grid, exclusion, etc. Some of those possibilities will now be explored.</p> <h4 id="put-the-notes-in-the-margin-boxes" tabindex="-1">Put the notes in the margin boxes</h4> <p>Sometimes the note area doesn't even need to be declared. Using the <code>element()</code> function, the margin-boxes can now receive the content of the <code>note</code> elements. Let’s look at an example: the following rules result in the placement of the note elements inside the left-top margin box. Margin and text alignment of the note elements are set to the note element itself and padding of the margin box are set in <code>@left-top</code> at-rule.</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@left-top</span></span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>sidenote<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">padding</span><span class="token punctuation">:</span> 5mm<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.sidenote</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>sidenote<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">margin-bottom</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span><br><span class="token property">text-align</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/notes_margin-box.png"></figure> <h4 id="use-of-float-pages" tabindex="-1">Use of float pages</h4> <p><a href="https://www.w3.org/TR/css-page-floats-3/">CSS Page float</a> specifications add some values to the <code>float</code> property to positioning element in a page context and propose the <a href="https://www.w3.org/TR/css-page-floats-3/#propdef-float-reference"> <code>float-reference</code> property</a> to indicate the &quot;reference container&quot; for a floated element. Extensive use will be made of these properties in the following examples.</p> <p>First, it can be used to create classical footnotes. The following code sets the default values of properties for <code>@note-area</code> and places notes at the bottom of the page:</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@note-area</span></span> <span class="token punctuation">{</span><br><span class="token property">float</span><span class="token punctuation">:</span> bottom<span class="token punctuation">;</span><br><span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><br><span class="token property">max-height</span><span class="token punctuation">:</span> 80%<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>Using float on the page and negative margins can be helpful in creating the note area half on margin, half on text content.</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@note-area</span></span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>sidenotes<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">float</span><span class="token punctuation">:</span> top right<span class="token punctuation">;</span><br><span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 42mm<span class="token punctuation">;</span><br><span class="token property">margin-right</span><span class="token punctuation">:</span> -30mm<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token selector">notes</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>sidenotes<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/notes_sidenotes.png"></figure> <p>Since a note area is a box, it's possible to layout the area itself (with columns for example).</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@note</span></span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>notes<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><br><span class="token property">float</span><span class="token punctuation">:</span> bottom right<span class="token punctuation">;</span><br><span class="token property">page-reference</span><span class="token punctuation">:</span> float<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span><br><span class="token property">columns</span><span class="token punctuation">:</span> 2<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token selector">notes</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>notes<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/notes_note-area-columns.png"></figure> <h4 id="multiple-notes-areas-in-a-page" tabindex="-1">Multiple notes areas in a page</h4> <p>There are already a lot of use cases in critical editions where you can find multiple kind of notes (bibliographical references, explanations, etc.) The <code>@note-area</code> at-rules declaration make multiples notes easier by mixing multiple note areas in the same page context. The <code>@note-area</code> may be followed by a custom identifier if wanted.</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@note</span> refsA</span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>refsA<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">float</span><span class="token punctuation">:</span> bottom left<span class="token punctuation">;</span><br><span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 30mm<span class="token punctuation">;</span><br><span class="token property">margin-left</span><span class="token punctuation">:</span> -12mm<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token atrule"><span class="token rule">@note</span> refsB</span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>refsB<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">float</span><span class="token punctuation">:</span> bottom right<span class="token punctuation">;</span><br><span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 60mm<span class="token punctuation">;</span><br><span class="token property">columns</span><span class="token punctuation">:</span> 2<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token selector">note.refs-catA</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>refsA<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">note.refs-catB</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>refsB<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/notes_multiple-1.png"></figure> <p>In the other following example, a new value <code>line</code> is added to the <code>float-reference</code> property. This allows creation of marginal notes, i.e., notes paced to one side of the text with its first line on the same height of the flow that contains the note-call.</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@left-top</span></span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>refs<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span> <br> <span class="token punctuation">}</span><br><span class="token atrule"><span class="token rule">@bottom-left</span></span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>footnotes<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><br><span class="token property">vertical-align</span><span class="token punctuation">:</span> bottom<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token selector">note.refs</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>refs<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">float-reference</span><span class="token punctuation">:</span> line<span class="token punctuation">;</span><br><span class="token property">width</span><span class="token punctuation">:</span> 50mm<span class="token punctuation">;</span><br><span class="token property">padding-left</span><span class="token punctuation">:</span> 50mm<span class="token punctuation">:</span><br><span class="token punctuation">}</span><br><br><span class="token selector">note.footnotes</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>footnotes<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/notes_multiple-2.png"></figure> <h4 id="notes-for-multi-column-layout" tabindex="-1">Notes for multi-column layout</h4> <p>In a multi-column layout, note elements may have to be displayed at the bottom of each column. This means that multiple note areas might have to be created for the same fragmented flow.</p> <p>Because a column is a anonymous box, there is currently no way in CSS to target a particular column of a multi-column element. This can be fixed by using the <a href="https://www.w3.org/TR/css-page-floats-3/">CSS Page float</a> properties. The <a href="https://www.w3.org/TR/css-page-floats-3/#propdef-float-reference"><code>float-reference</code> property</a> indicates the &quot;reference container&quot; for a floated element and the value <code>column</code> indicates that the float reference is the column in which the floated element is placed in a multi-column environment.</p> <p>This reference can be used to indicate creation of note areas in the columns of the page where the note appears. As many boxes as necessary are created on each column. All the note areas have the same properties and can be targeted by one <code>@note-area</code> rule only.</p> <pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span><br><span class="token atrule"><span class="token rule">@note-area</span></span> <span class="token punctuation">{</span><br><span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">element</span><span class="token punctuation">(</span>notes<span class="token punctuation">,</span> all-once<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token property">float</span><span class="token punctuation">:</span> bottom<span class="token punctuation">;</span><br><span class="token property">float-reference</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#content</span> <span class="token punctuation">{</span><br><span class="token property">columns</span><span class="token punctuation">:</span> 3<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#content note.notes</span> <span class="token punctuation">{</span><br><span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">note</span><span class="token punctuation">(</span>notes<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/notes_columns.png"></figure> <p>Here are some examples of the CSS layout facilities used to layout notes areas of paginated media. Of course, the CSS layout facilities can also be used in continuous media on the pseudo element <code>::area-note</code>. Over to you to use your imagination.</p> <p>This article is an overview of the specifications imagined for the notes, and is an extract from the <a href="https://github.com/w3c/css-print/issues/3">issue</a> published in the GitHub of the CSS print community group. That issue provides more detail than the few properties we have presented here and a few others (note policy for example). You are invited to take a look at this more complete document and comment on it. The specifications are a community work and it is only together that we will be able to improve them.</p> Pagedjs 0.1.40 2020-04-01T17:16:44Z https://pagedjs.org/posts/en/pagedjs-0.1.40/ <h2 id="new-release!" tabindex="-1">New release!</h2> <p>The 0.1.40 is now available to download from <a href="https://unpkg.com">unpkg</a> or <a href="https://www.npmjs.com/package/pagedjs">npm</a> (and on our <a href="https://pagedjs.org/documentation/releases">release page</a>).</p> <p>In this release:</p> <ul> <li>@julientaq added support for the <code>position: fixed</code> property: if one of your element is set as <code>fixed</code>, it will be repeated on all pages without having to struggle with <code>margin-boxes</code>, <code>position: running</code> or <code>string-set</code>. Be aware that the origin will always be the page, thus you’ll need to set up negative margins to your element to bring it in the bleeds.</li> <li>Antonio Norman (@antman3351) <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/issues/180">found a bug and its fix</a>, when you had multiple <code>string</code> elements on the same page.</li> <li>Support for period in <code>id</code> attribute: <code>.</code> is for <code>class</code> and <code>#</code> is for <code>id</code>. But the specs allow you to use a <code>.</code> in an <code>id</code>!<br> Paged.js can now handle <code>&lt;p id=&quot;#this.paragraph&quot;&gt;</code> without crashing.</li> <li>@Stouffi fixed a couple of bugs in the chunker, and documented those quite well <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/101">here</a> and [there]<a href="https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/98">https://gitlab.coko.foundation/pagedjs/pagedjs/merge_requests/98</a>).</li> <li>Fred Chasen (@fchasen) update the Jest infrastructure so tests are now running fine.</li> <li>Guillaume (@mogztter) wanted to be sure that we’d all follow the best practices without having to spend hours checking our spaces/tabs issues, so he set up eslint, put is hands in 58 files, cleaned all the tabulation issues we had in the code and updated.</li> </ul> <p>Thanks to our awesome contributors you can now enjoy this new version.</p> <p>See you all very soon!</p> Finding letters for Atla 2020-03-08T15:53:38Z https://pagedjs.org/posts/en/finding-letters-for-atla/ <p><em>Creating Templates</em> is a series of articles in which one designer will explain the choices they made for a collection or a book, following the process from the typical design workflow to the output in modern typesetting using Paged.js. For the first article of the series, we’ll look at how Julien designed a template to be used in Editoria by Atla Open Press.<br> Established in 1946 as the American Theological Library Association, Atla is a membership association of librarians and information professionals, and a producer of research tools, committed to advancing the study of religion and theology.</p> <p>Atla Open Press publishes open access books, journals, and other serials that cover subjects at the intersection of librarianship and religious and theological studies. Their books help to shape, guide and support innovative library services and enhance professional development for theological librarians and the field of religious studies.</p> <p>Atla is moving its publishing workflow toward using <a href="https://www.editoria.pub">Editoria</a>, the community-driven platform to make books that Coko is working on. As early adopters of Editoria, Atla are an example of how you can change your publishing workflow by giving more space to collaboration with anyone involved in the making of the book. As part as their collaboration with Coko, Julien worked with the folks at Atla to design a template to be used in Editoria, ready to be used with Paged.js. Atla have now offered the template back to the community with an open source license (the template will be released soon).</p> <h3 id="the-physical-book" tabindex="-1">The physical book</h3> <p>The primary form of the books published by Atla Open Press is digital: epub and PDF made for the screen, and the books are downloadable from their website. But the books are also produced as printed material, using Print On Demand services (or personal printers).</p> <p>When the team started to work on the template, we explored an array of potential final output sizes for the book, and eventually we decided to go with a standard 6 × 9 inches (15.2 × 22.8 cm). Following the standard reduces the risk of errors when working with different printers, and if the reader needs to print the document at home, it’s pretty easy to put 4 pages per sheet of paper, reducing the waste without losing too much readability.</p> <p>Once you have the size of your book, you’re ready to work. But what happens next is never a nice and easy sequence of steps to follow. It’s more like a series of trails and paths that we follow at the same time: fonts, font-size, leading, margins, etc. This production process is where the tension between aesthetics and readability has to be taken into account.</p> <p>The first step is to figure out the number of characters which can be put on a page. The number of characters per line is the element that will determine a great part of the layout, so it needs to be carefully considered. Most books for scholars allow for more than the 55/65 characters per line usually advised for ebooks. With that in mind, letter choice can begin..</p> <h3 id="the-typefaces" tabindex="-1">The typefaces</h3> <p>Typesetting is the act of putting letters on paper in a way that gracefully mixes legibility and aesthetics. Therefore, it starts with drawn letters. Always.</p> <p>Here is a useful checklist:</p> <ol> <li>Remember the kind of letters you’ll need to work with.</li> </ol> <p>How many of letters outside of the Latin glyphset will you need? Is your content only English, or do you have letters from extended Latin, or Greek? What about Cyrillic? Does it include a section of an old transcript from oral languages that has just been included in the Unicode? Since the books Alta publishes are about theology and religions, it’s not gambling to say that there will be a lot of non-English characters.</p> <ol start="2"> <li>Remember every member of the family you’re going to need</li> </ol> <p>Sometimes you need to emphasise one part of the text, or show that a word has a different meaning or comes from another language. While an emphasis is not always set as italic, that has become over the year a kind of a standard: the <code>em</code> HTML element for the emphasis is by default an italic in almost all browsers.</p> <p>Therefore, Roman letters are not enough for this template. So you need to be sure that the letters will have those styles available. Italic is the minimum. Bold is seldom used for emphasis in ebooks as it’s often not subtle enough, but it’s always useful to have that option for headers and structure.</p> <ol start="3"> <li>Remember the type color</li> </ol> <p>Whatever font you choose, you’ll need to have the right balance between white and black on the page (<em>ie</em> the type color). That balance depends on how the type is set up: the drawings of the letters, the number of characters per line, the options for the justification: spacing, kerning, the width of the white space, etc. Depending on the content, you may want to have a darker feeling, that your page is filled with content, or you may want to be precious and have a lot of white space, giving a feeling of luxury. A good type color is one that is not too black, not too white, and dynamic enough to never feel grey.</p> <ol start="4"> <li>Remember that the look of the book is different than the experience of the book</li> </ol> <p>I think that Tarantino said once that he never watched a movie without knowing it was a movie. I can say that I have never read a book without knowing it was a book: my designer’s eyes always get the over all feeling first: the type color, the font chosen, the margins, the alignments, etc. I understand the book before I start reading it. But here is the trick: a book can feel well designed and perfectly crafted, but the experience you’ll get from its reading may be different. So don’t forget to print and test and have a good look, print again, check again, until you’re happy with the feeling as much as the look.</p> <h4 id="choosing-the-right-fonts" tabindex="-1">Choosing the right fonts</h4> <p>As a designer, I used to follow every link that led to a new typeface or a new foundry. I bought fonts just because I liked their look even if I had no clue about how I would use them. So I got to look at fonts all day long, teaching my eye to look for specificities and to remember the feelings those could give. Choosing a font is all about finding the tiniest bit of the letter that will give the first impression on the book.</p> <p>In Atla’s case, my first idea was to look at the classics. Going with a well-known letterform will give a sense of trust and truthfulness. But at the same time, I wanted to find something that was representative of the personality of the publishing house. Warm and friendly. Serious and friendly, the people you want to work with. And then also, there is the need for the font to support a wide range of letters and glyphs, and that’s generally the place to start.</p> <p>I started by looking at what I knew would answer that question, first choice being the <a href="https://brill.com/page/1228?language=en">Brill</a> typeface, designed by the folks at <a href="http://www.tiro.com/">Tiro Typeworks</a>. Significant factors were firstly, because it supports Latin, Greek and Cyrillic, and secondly because each letter has been designed with care. However, you can’t really use that font for an Open Source project: as the Brill end user license agreement specifies that the font can only be used in a non-commercial environment, so that rules out using it for Atla.</p> <p>Thankfully, over the last 20 years, there has been a lot of movement in the world of open source type foundries, and there is even a specific license, the SIL Open Font License (OFL), in use since 2005. I decided to investigate what the foundries offered, and I have spent a good deal of time finding what is available and identifying what would be a good fit for Atla.</p> <p>The <a href="https://fontlibrary.org/">font library</a> is often a good place to start looking for open source fonts. It includes a CDN that let you test your fonts in your files without having to build any <code>@font-face</code> functions. Language support generally needs to be a priority especially for as much of the Latin as possible, and the more languages the better, starting with Greek and Cyrillic, as they are often designed with the same tools and movements as Latin is designed with. Most of the time when you look at your content, the letters coming from another language will fit right in place.</p> <h5 id="eb-garamond" tabindex="-1">EB Garamond</h5> <p>First, the classic of the classics, the Garamond, but the one under OFL licence, <a href="http://www.georgduffner.at/ebgaramond/">EB Garamond</a>. The glyph set and the open-type features are quite interesting. These are in optical sizes: you wouldn’t use the same glyphs for a text set in 12pt or for a text set in 10pt, which is a tremendous work. But there is one caveat: there is no bold, so that would leave less options for the headings structure.</p> <figure><img src="https://pagedjs.org/images/EBgaramond.png" class="eighty"></figure> <p>The other issue with the Garamond is the hardness of its shapes: the plume and the calligraphic gesture behind the letters survived in the digitization of those letters. While this adds a lot of authority to the letters, it doesn’t give the warmth and kindness I am looking for.</p> <h5 id="noto-serif-%26-linguistics-pro" tabindex="-1">Noto Serif &amp; Linguistics Pro</h5> <p><a href="https://www.google.com/get/noto/">Noto fonts</a> is an attempt from Google to have one super font family that supports all languages ever written with the same look and feel. While this seems to be an impossible task, Noto fonts already supports a wide variety of languages, which makes it a pretty good starting point to show international content. For example:</p> <figure><img src="https://pagedjs.org/images/NotoSerif.png" class="eighty"></figure> <p>A font is like a color: it carries a lot of feeling in itself, but to have the most complete overview of its specificities, you need to compare it with another. So I you need to check the foundries.</p> <p>The other font I looked at was <a href="https://fontlibrary.org/en/font/linguistics-pro">Linguistics Pro</a>, the most recent take on the Utopia Nova. The story of those letters goes back to 1989 when Robert Slimbach designed the font for Adobe and licensed to the TeX Users Group (TUG) for free modification and redistribution. Over the years, it has evolved to include polytonic Greek, modern and traditional Cyrillic, Vietnamese, among others, and was re-released in 2016 by Stefan Peev. It includes italic, bold and bold-italic, which is useful for headings.</p> <figure><img src="https://pagedjs.org/images/Linguistics.png" class="eighty"></figure> <p>While the two fonts feel close over all in look and feel, they turn out to be very different when you inspect them carefully:</p> <figure><img src="https://pagedjs.org/images/notovslinguistics.svg" class="eighty"></figure> <p>Noto Sans is more friendly than Garamond or Linguistics. It’s a modern serif that brings back a lot of manual gestures: the terminals of the f, r or capital S are all about calligraphic feelings, while the mechanical serifs are all about math and geometry. Those two characteristics are pretty useful when it comes to sharing shapes between letters from different parts of the world.</p> <p>Linguistics Pro, on the other hand feels less modern. It’s based on a character that could have been released at the end of the 18th century when typographers were slightly moving away from their calligraphic roots to enter the world of rationality that was coming. Thus, we can find in those font characters, the characteristics of a scientifically drawn letter and the humanity of rounded serif terminals, never being sharp: a friendly but trusty face.</p> <p>The last step is checking the fonts in context of a real paragraph, using text you can actually read, and no <em>lorem ipsum</em> placeholders.</p> <p>The sizes of the letters are different: the Linguistics Pro family has a bigger ratio between the ascenders and the x-height than Noto. This gives a lighter feeling: the text will need less leading to achieve a good type black, and we’ll have more lines of text per page, which is a huge win when it comes to monograph books: reducing the amount of paper needed without losing readability is the real thing we’re trying to achieve.</p> <figure><img src="https://pagedjs.org/images/paragraph.svg" class="eighty"></figure> <p>So let’s try Linguistic Pro first, and we’ll see if we need to change later on.</p> <p>Spoiler: <a href="https://books.atla.com/atlapress/catalog/view/33/30/198-1">it works fine</a>.</p> <p><em>The next article of the series will be all about the amount of content we can put on a page, defining margins, headings, and page types. See you all very soon.</em></p> Welcome to paged.js 0.1.38 2020-02-25T11:25:19Z https://pagedjs.org/posts/en/welcome-to-paged.js-0.1.38/ <!-- We just released a new version of Paged.js! The 0.1.38 is now available to download from [https://unpkg.com](https://unpkg.com/browse/[email protected]/dist/) or you can install it using [npm](https://www.npmjs.com/package/pagedjs). --> <h2 id="new-in-this-release%3A" tabindex="-1">New in this release:</h2> <p><em>Somehow, the release has been made before the code for the string-update feature was merged. Since the release , it will be part of the 0.1.39. If you want to use that code today, you can download it from <a href="https://pagedjs.org/documentation/releases">here</a></em></p> <p>This is a minor release which includes one item:</p> <ul> <li>updated our support for the string-set property. Following the W3C specs, you have now more options to define which title will appear on the page. Here is the schema that helped us implement it, courtesy of Julie Blanc.</li> </ul> <figure> <img src="https://pagedjs.org/posts/en/welcome-to-paged.js-0.1.38/images/graphic-issue-string.png"></figure> <h2 id="additional-items%3A" tabindex="-1">Additional items:</h2> <ul> <li> <p>Thomas Parisot and Fred set up an automated workflow to publish new versions when the gitlab codebase is updated. This will help us provide better support to the people who implement Paged.js in other tools or workflows.</p> </li> <li> <p>Pagedjs-CLI (now in its version 0.0.10) is updated to support post-processing PDF. As a first feature, we’re now able to define the crop box and the margin boxes of the PDF. Also if you use the CLI your PDF will now be tagged!</p> </li> <li> <p>We’re also documenting the roadmap for the coming months to give you a better overview of where we’re going, and how you could help if you want to. We’ll share it soon!</p> </li> </ul> <h2 id="updated-documentation" tabindex="-1">Updated Documentation</h2> <p>We have updated the list of the Paged media features that paged.js supports. It contains links to some examples we made and to the W3C specifications. You’ll find everything in our <a href="http://localhost:1313/documentation/cheatsheet/">documentation</a>. Please drop us a line if something is unclear, we’ll be happy to make a tutorial for it.</p> <h2 id="hugo-component" tabindex="-1">Hugo Component</h2> <p>For those who never heard of it, Hugo is an open source static site generator written in Go, blazing fast and pretty efficient. It’s packed with a ton of features and ideas so smart that building the paged.js website with it has been a pleasure. One of the features we need for the website is Paged.js integration to make books out of the HTML. Thus, we made an implementation of <a href="https://gitlab.coko.foundation/julientaq/pagedjs-hugo">Paged.js for Hugo</a>. Hugo has a really well thought out theme engine: to be able to use the print script you only need to add the information in your config theme, <em>et voilà</em>. It’s still early and experimental, but if you hit the top right button on this page, you can see what it does. Feel free to raise a GitLab issue if you find any.</p> <h2 id="paged.js-on-reddit" tabindex="-1">Paged.js on Reddit</h2> <p>Last week, we were mentioned on <a href="https://www.reddit.com/r/javascript/comments/f5syqi/pagedjs_a_free_and_open_source_javascript_library/">Reddit</a>! We ended up answering some questions as an improvised Q&amp;A session. Since keeping track of things on Reddit is not easy, here are a quick overview of some questions and our responses.</p> <h3 id="from-%2Fu%2Fharmonicascendant" tabindex="-1">From /u/HarmonicAscendant</h3> <blockquote> <p>“I am wondering how it could best work with markdown &gt; pandoc to HTML &gt; paged.js to PDF with Chromium”.</p> </blockquote> <p>Paged.js is a js library, you can use it in any workflow :) For instance, the paged.js website is developed using Hugo, documentation is written in Markdown, and the result is a website, to which we added a button to run paged.js, preview the book in the browser and make a PDF by printing the page. And yes, using CSS for the layout is easier than going with Tex :) You can make a PDF with any HTML source :)</p> <h4 id="from-%2Fu%2Febichuhamster" tabindex="-1">From /u/ebichuhamster</h4> <blockquote> <p>“Isn’t this a thing already just using css?”</p> </blockquote> <p>It should be. W3C wrote (and keep writing) a lot of specifications for print, but browsers haven’t really implemented those. That’s why we’re making a polyfill: you can write the CSS following the specifications even if they’re not implemented yet and call Paged.js to transform those into rules that our browsers can understand today. When the browsers will have implemented all the things we need, we’ll stop working on Paged.js (but don’t expect to see that to happen in a near future).</p> <h4 id="from-%2Fu%2Fbrainbag" tabindex="-1">From /u/brainbag</h4> <blockquote> <p>“Could you say more about how you implemented this? We're using puppeteer to render PDFs server-side, but I've been waiting for client side css to have better handling so we can drop it.”</p> </blockquote> <p>You can check the not so-well-hidden button top right <a href="https://www.pagedjs.org/posts/2020-02-19-toc/">here</a> to see Paged.js in action. It will run paged.js, show the preview in the browser and offer you to print as PDF. Client side PDF rendering! A small warning though: Chromium and alike are the only browsers that let you print in custom paper size (A5, Square, custom, etc.). In the case that you’d like to set the page size at A4 or letter, you’ll be safe in almost every browser.</p> <h4 id="from-%2Fu%2Fdhimmel" tabindex="-1">From /u/dhimmel</h4> <blockquote> <p>“[What about] Numbering pages on the output PDF”</p> </blockquote> <p>This is pretty basic Paged media specs stuff, we got you covered in the doc. (you may want to read from the top of the page though) <a href="https://www.pagedjs.org/documentation/07-generated-content-in-margin-boxes/#page-counter">https://www.pagedjs.org/documentation/07-generated-content-in-margin-boxes/#page-counter</a></p> <blockquote> <p>“Numbering lines on the output PDF”</p> </blockquote> <p>A solution build by the community: <a href="https://github.com/rstudio/pagedown/issues/115">https://github.com/rstudio/pagedown/issues/115</a> I’ll make a post about that. We also have a simple solution to build a baseline grid: <a href="https://www.pagedjs.org/images/linecount.png">https://www.pagedjs.org/images/linecount.png</a></p> <blockquote> <p>”Floating figures and tables to avoid large chunks of whitespace”</p> </blockquote> <p>We do have solutions to do that, but it depends on your content and how you want it to behave. Floating top is pretty much easy to do. But Julie, our specialist of specifications wrote quite a good article about that: <a href="https://www.pagedjs.org/page-floats/">https://www.pagedjs.org/page-floats/</a></p> <blockquote> <p>“multiple columns on PDF pages”</p> </blockquote> <p>Yes sir :) We’re using the browser and pages are made using css grid and flex, so you can do pretty much what you would do in a browser for screen. I’ll try to find some examples in the coming days.</p> <h4 id="from-%2Fu%2Fserei" tabindex="-1">From /u/Serei</h4> <blockquote> <p>“Is it possible to make footnotes that appear at the bottom of the current page?”</p> </blockquote> <p>The W3C specs for the footnotes are still being finalised, but we are actively working on some solutions to follow these specs (even joining the w3c print working group to make those evolve). We have some solutions for margin notes <a href="https://gitlab.coko.foundation/pagedjs/experiments/tree/master/margin-notes">https://gitlab.coko.foundation/pagedjs/experiments/tree/master/margin-notes</a> and we made a couple of books with footnotes, but it needed some manual works to make sure the layout was great.</p> <p>We’re now upgrading the library core to handle multiple flows and float-top and bottom, which would allow us to have footnotes, and ones that would run on multiple pages if needed. We’ll make an article about that soon.</p> <h2 id="one-more-for-the-road" tabindex="-1">One more for the road</h2> <p>The excellent <a href="https://hugogiraudel.com">Hugo “Kitty” Giraudel</a> made a tool to turn any CSS selector into proper English. If you don’t understand why your CSS properties are not being applied, or if you only want to get better at targeting elements with precision, this is the webpage to consult: <a href="https://hugogiraudel.github.io/selectors-explained/">https://hugogiraudel.github.io/selectors-explained/</a>. It also includes the selector specificity score.</p> <p>And that’s all for this time folks, but we keep working.</p> <p>Stay tuned!</p> Return from Prague: the future of web to print 2020-02-18T11:02:48Z https://pagedjs.org/posts/en/return-from-prague:-the-future-of-web-to-print/ <h2 id="report-about-the-w3c-workshop-on-css-print" tabindex="-1">Report about the W3C Workshop on CSS Print</h2> <p>On Thursday, February 13th, a group of people gathered at the University of Economics in Prague (Czech Republic) to participate in the<a href="https://wiki.csswg.org/planning/print-workshop-2020">W3C Workshop on CSS Print</a> as a part of the XML Prague conference. The event was organized by Rachel Andrew, Jirka Kosek and Dave Cramer, members of the CSS working group. Between 30 and 40 people were present, showing a real interest in CSS print.</p> <p>The workshop started with a <a href="https://noti.st/rachelandrew/Hy20NS/introduction-to-the-css-working-group#sWtnkmF">presentation by Rachel Andrews</a>, talking about the work of the W3C about the creation of freely open standards for the Web and how the working groups operate, particularly the CSS working group. Rachel recalled that standards take time to set up, because of the specification process, but also because of the lack of funding for work on print specifications. She enumerated a list of possibilities for making things better. Anyone can and is allowed to contribute to specifications (no need to be part of W3C or need permission). Reading and commenting on <a href="https://github.com/w3c/csswg-drafts/issues">specifications issues</a> is a good start, as is showing use cases or developing web platform tests. It's also possible to contribute by providing examples and diagrams to specifications. If we want the specifications to improve, there's no secret; the W3C needs to find people to work on print-related specifications, testing and implementations.</p> <p>After Rachel, several people who had submitted their paper positions, gave shorter presentations about their work and the tools used with CSS print and paged media.</p> <ul> <li>Dave Cramer started <a href="https://lists.w3.org/Archives/Public/public-css-print/2020JanMar/att-0032/Cramer-PrintWorkshop-XMLPrague.pdf">with his work at Hachette Group</a>. Hachette have produced (many) PDFs with HTML and Print CSS over the last ten years. He also talked about the fluctuating implementations of paged media and generated content for paged media in web browsers.</li> <li>Michel Miller <a href="https://lists.w3.org/Archives/Public/public-css-print/2020JanMar/att-0035/CSSWG_Antenna_House_XML_Prague_2020.pdf">presented Antenna House</a> and their custom AH formatting engine used to make CSS and XSL-FO paged media outputs.</li> <li>Cornelia Kremlin and Katharina Udemadu <a href="https://lists.w3.org/Archives/Public/public-css-print/2020JanMar/att-0036/Compart-PositionPaper.pdf">presented Compart</a>, a supplier of document and content technology solutions. Compart is working on the creation of transactions documents using data from an XML data source to create multiple outputs, including PDF.</li> <li>Andreas Jung <a href="https://lists.w3.org/Archives/Public/public-css-print/2020JanMar/att-0034/01-part">presented his print-CSS. Rocks project</a>, a website where you can find information about tools that exist to create PDF outputs from HTML or XML content. The project offers tutorials and lessons and compares tools and implementations through small, simple tests.</li> <li>Liam Quin <a href="https://lists.w3.org/Archives/Public/public-css-print/2020JanMar/att-0041/02-css-workshop-prague.pdf">spoke on a more general level</a> about why pages matter in apps and websites and should be taken into account. He reminded us that the things that people need today are not only about pretty output but more importantly about functionality (initial caps, indexes, marginalia…).</li> <li>I also <a href="http://slides.julie-blanc.fr/20200213_W3C-prague.html">presented Paged.js</a>, how the library works and our position in relation to browsers and needs.</li> </ul> <p>All the presentations talked about CSS pain points, print requirements, and some useful specifications that are not yet implemented in any browser or tools (such as handling the initial letter, for example). There is a real need and there are still too many things we can't do today. A lot of specifications are missing in browsers and tools and adoption of the standards is slow. Many tools also develop their own specific extensions to meet the needs of their users (such as page float, footnotes in multi-columns…) and the compatibility between tools is limited. In short, there is a huge amount of work to be done for full use of CSS print and CSS paged media.</p> <p>A one-hour discussion involving all participants followed the presentations. Some questions which had been raised in the presentations, came up repeatedly:</p> <ul> <li>What are the missing parts and what can we do? How can we identify relevant features missing in Print CSS? Footnotes or mixed writing modes were often raised as examples where more work is needed.</li> <li>In the existing specifications, how can we best prioritize the various needs of implementation? For example, there's some low-hanging fruit, and things Web developers will find useful (e.g. CSS exclusions), maybe we should start with that, because there's going to be strong interest in that.</li> <li>Another example, @page size bug is a major issue in some browsers, impossible to hack, if we don't start there, the rest might be for nothing.</li> <li>You can also see other questions and points by reading position papers and/or the transcription of the conversation <a href="https://www.w3.org/2020/02/13-printcss-minutes.html">here</a>.</li> </ul> <p>To date, the specifications for print/paged media have been developed under the flag of the (CSS WG). The group also works on a lot of other things; print and paginated media are not necessarily its priority. The work in this area is lost in the mass, not very visible, and the status of CSS draft specifications are unclear (unmaintained, work-in-progress, discontinued?) For example, Dave Cramer is now the only editor of generated content for paged media module and needs help. Writing layout specs is hard, and we need to figure out how to get enough people to contribute</p> <p>So, during the final conversation, rather than make a wish list of new specifications, we focused on the process: how can we work more effectively with the CSS working group (CSS WG)?</p> <p>As Liam Quin said in the conclusion of his presentation, &quot;nothing will go forward until the stakeholders are proactive.&quot; During this workshop, we could see that there is a core of people very interested in what's going on today with CSS for print and paged media. At the end of the workshop, a new community group was established as a place of our own to raise issues before bringing items to the CSS working group. Dave Cramer, supported by some of the participants, proposed this new group be added to the W3C as the CSS Print Community Group.</p> <p>The purpose of the group is to “work together to gather use cases, help with specifications, and advocate for more and better implementations”. At the end of the day, the community group was launched and accepted in the list of the current W3C community group: <a href="https://www.w3.org/community/cssprint/.">https://www.w3.org/community/cssprint/</a>. You don't need to be part of W3C to join it, so jump in!</p> Our position paper for the W3C CSS print workshop 2020-02-14T10:19:56Z https://pagedjs.org/posts/en/our-position-paper-for-the-w3c-css-print-workshop/ <h1 id="paged.js" tabindex="-1">Paged.js</h1> <p><em>Position paper for the W3C Workshop on CSS Print (February 13th, 2020)</em></p> <p>Paged.js is a free and open source JavaScript library that paginates content in the browser to create PDF output from any HTML content. It was developed to meet the requirements encountered by Adam Hyde, Fred Chasen and Julien Taquet when building the book production platform Editoria: an open source solution was wanted and there were no existing solutions which did what Editoria needed. Right around that time, Julie Blanc joined the team and the four of us built it together.</p> <p>Adam has spent years on helping organizations to define their own publishing workflows, and building publishing platforms. Fred has been working in the publishing field for quite a while and his work on epub.js has proven invaluable. Julien has been producing books with html and css for more than five years using a variety of tools, either at Book Sprints Ltd or for Coko. Julie was working on her PHD on evolution of design in typesetting and she was able to focus her research on the specifications which would be needed for the Paged.js project and how they might evolve.</p> <p>Before the team jumped into the work, we decided to discuss the project first with the people in the field, and in January 2018, we organized the first such meeting at the MIT Press in Cambridge (MA). We were able to share our experience, examine existing solutions and share some of the experiments Fred has been working on.</p> <p>Subequently, we started the next stage of development armed with the knowledge gained from that community meeting.</p> <h2 id="paged.js%3A-a-polyfill-for-print-specifications" tabindex="-1">Paged.js: a polyfill for print specifications</h2> <p>Following the Paged Media standards published by the W3C (ie the Paged Media Module, and the Generated Content for Paged Media Module), Paged.js acts as a polyfill for the CSS modules to print content in ways that are not normally supported by browsers.</p> <h3 id="the-technical-bit-behind-paged.js" tabindex="-1">The technical bit behind Paged.js</h3> <p>When Paged.js starts on a webpage, it reads the HTML content and the CSS rules defined in the links or the header, and starts the paginating work by modifying the DOM structure, adding HTML elements to build pages, and translating the CSS to render the layout. The HTML source doesn’t need any specific properties or elements, as all the layout is defined in the CSS.</p> <p>The library interprets the declarations and translates them into CSS and JavaScript, either by converting them to common CSS styles or by replacing them with JavaScript implementations. To achieve this, the page model from the Paged Media Specifications has been rebuilt using grid and flex-box, and since we use the browser to render our pages, we can leverage all the work put into implementing other CSS specifications such as flex-box, grid, svg management, etc.</p> <h3 id="three-modules" tabindex="-1">Three modules</h3> <p>Paged.js is made of three modules that work hand in hand:</p> <ul> <li><strong>the chunker</strong> that fragments the content into discrete pages,</li> <li><strong>the polisher</strong> that transforms the CSS declarations into ones the browser understands</li> <li><strong>the previewer</strong> which shows how the book will be printed in the browser.</li> </ul> <h4 id="the-chunker" tabindex="-1">The chunker</h4> <p>The chunker is the part of Paged.js that manages the fragmentation of the content to flow it into pages. To do so, it takes all the rendered content (with their css styles), creates a page (following the page model of the specs), and pust the content in the content area.</p> <p>To find where the content needs to be fragmented, CSS-columns are used: each page is a column with width and height set to be exactly as the page content area will be in the paginated output. Once an element overflows the page height, a new page is created, and the rest of the content goes in. The chunker keeps doing that until all the content is laid out. Once the script is done, the content area of each page is an independent HTML element. Using CSS columns allows easier access to the fragmentation properties already implemented in browsers, such as page-breaks, element properties, or widows and orphans.</p> <h4 id="the-polisher" tabindex="-1">The polisher</h4> <p>Thanks to the CSStree library, the polisher parses the CSS and translates the CSS stylesheet into classes that the browser understands. For example, the properties of the <code>@page</code> rules are turned into HTML classes. In other words, you provide CSS that conforms to the standards, and Paged.js applies those on the transformed DOM.</p> <p>This way, the system is able to handle running headers, page counters, or any CSS-generated content functions with CSS custom properties from the DOM. Paged.js also adds references to every node (for example, data references to find elements that are split between pages). This gives a complete control over the page layout and users can access these elements in CSS or Javascript with their classes if they want to go further with Paged.js and add their own functions.</p> <h4 id="the-previewer" tabindex="-1">The previewer</h4> <p>The previewer makes it possible to have a visual preview of the printed output directly in the browser with a graphical interface. This allows designers to access development tools to make changes and control the rendering of the composition. Using simple css properties, pagesare shown as facing pages, single ones on top of the other, the same way you would see those in the classic book design applications.</p> <p>But Paged.js can also be run in a fully automated workflow where the PDF is generated server side. This makes use of a command line version of Paged.js based on Puppeteer to open a Chromium headlesss instance and create the PDF files.</p> <h4 id="plug-into-paged.js" tabindex="-1">Plug into paged.js</h4> <p>Paged.js is a modular library that runs each part of the code in a specific sequence: from the parsing of the content and styles, when a new page is created, when a new element is added on the page, when a page has finished rendering, to when the library has finished its job. This lets you add any custom module you may need. For example, to set the image as <code>page-float: top</code> you can follow this simple algorithm: when a <code>img</code> or a <code>figure</code> element gets rendered, remove it from the flow, and prepend it as the first element on the page. The same idea can be used to create a baseline rhythm where you can add <code>padding-top</code> to element which are not starting on the grid.</p> <h2 id="a-community" tabindex="-1">A community</h2> <p>For the last two years, the Paged.js project team has put a lot of effort into keeping the community informed and engaged. We regularly meet for a Mattermost chat with around 150 people, where we discuss issues, report on updates, code and plans for the various projects that are using Paged.js.</p> <h3 id="projects" tabindex="-1">Projects</h3> <p>Coko’s <a href="https://editoria.pub/"><strong>Editoria</strong></a> is the first project to include Paged.js export. With the developers, we’ve been working on providing support to explain how the library works and how they could add a templates manager, live update of the export when the css changes, etc. The users of Editoria are publishing houses who have a high expectations when it comes to the pdf output, and that offers us a wide variety of use cases.</p> <p><a href="https://github.com/rstudio/pagedown"><strong>Pagedown</strong></a> is another interresting project that uses Paged.js to generate PDF for the Rstudio community. RStudio develops free and open tools for R, and enterprise-ready professional products for teams who use both R and Python to scale and share their work. Romalin Lesur and Yihui Xie have been advocating for HTML and CSS instead of Latex, and the monthly download numbers are pretty high.</p> <p><a href="https://www.hederis.com/"><strong>Hederis</strong></a>, a platform to design books and publish PDFs uses Paged.js for previewing and updating the books. Hederis project founder Nelly McKesson was part of the Cambridge meeting and came to meet us during an Editoria event in San Francisco last year. She’s also contributing to the project codebase.</p> <p><a href="https://github.com/Mogztter/asciidoctor-pdf.js"><strong>AsciidocPDF</strong></a> is a PDF converter for AsciiDoc based on web technologies. It allows complex layouts to be defined with CSS and JavaScript, while writing the content in AsciiDoc. Guillaume Grossetie and Thomas Parisot who are maintaining the tool are actually contributing back to Paged.js, offering us a tremendous help.</p> <p><a href="https://panwriter.com/"><strong>PanWriter</strong></a> and <a href="https://peritext.github.io/ovide/"><strong>Ovide</strong></a> also use Paged.js, and we’re discussing developments with <a href="http://blog.sens-public.org/marcellovitalirosati/stylo/"><strong>Stylo</strong></a>, and others projects we’re helping.</p> <p>Julie Blanc also worked on the <a href="https://villachiragan.saintraymond.toulouse.fr/"><strong>Villa Chiragan</strong></a> project that presented sculptures of the museum on the web. You can check the printer version if you print on any webpage, and you can also check what she managed to do using Paged.js <a href="https://villachiragan.saintraymond.toulouse.fr/impression">here</a>.</p> <h3 id="workshop%2C-teaching-and-lectures" tabindex="-1">Workshop, teaching and lectures</h3> <p>Since the beginning of the Paged.js project, the team has been part of a number of different events to introduce paged.js, from publishing events (such as the <a href="https://www.youtube.com/watch?v=3SvfARdZRA4">digital publishing summit</a> in Paris) to open source meetings and conferences (<em>Write the docs</em> at Mozilla's office in Paris, <em>journées du logiciel libre</em> in Lyon, <em>Fosdem</em>, etc.) to present the project, or to discuss with other members of the community.</p> <p>We also spent quite some time organizing workshops and meetings to show Paged.js to editors and designers. Many workshops also take place in art and design schools so that future professionals are trained in these ways of doing. We hope to do more in the coming months and years.</p> <p>By providing more examples of what can be accomplished using print CSS, we hope to advocate for better support of print-related standards in browser engines. It's our first goal, until then we will provide support via our work.</p> <p>During the second half of last year, we rewrote the documentation, and made a new website (we’re working on it and hope for a release pretty soon). You can have a quick preview <a href="http://onepager--hungry-boyd-59d45a.netlify.com/">here</a> to have an idea of how it will be. We’ll also provides templates, insight into Paged Media specs, and use it as a platform to write for anyone who'd like to write a piece about what we're doing. We’ll also reprint some of the articles from<a href="http://www.pagedmedia.org/"> www.pagedmedia.org</a> as a way to highlight that information.</p> <p>Following the same idea, the <a href="https://gitlab.coko.foundation/tools/pagedjs">repository</a> for Paged.js also contains some <a href="https://gitlab.coko.foundation/pagedjs/experiments">examples</a> which provide insight into how to build a table of contents, how to follow a baseline snapping layout, or use hooks, and even a first implementation of the footnotes.</p> <h3 id="the-future-of-paged.js" tabindex="-1">The future of Paged.js</h3> <p>As we now have a more mature library, we have stared to look at where we’d like to go with Paged Media. Therefore, as the time of writing this, we’re joining the W3C under the flag of the Cabbage Tree Lab as we want to be part of the continuing standards conversation.</p> <p>Julien is now working on the community side of things, organizing events and fixing issues, keeping everyone happy while the codebase evolves. Julie is writing new specs ideas that we’ll hope to share and discuss as soon as possible. Fred is rewriting the whole chunker, as we’d like to support multiple flows, floats and offer a better footnote solution than the one we have now.</p> <p>When this is done, we’ll layout a roadmap (more like a subway map) so anyone can contribute where they think they can best do so. Members of the community are also starting to offer services to those who may need custom development or specific stylesheest, as more and more users are getting confortable with designing books in browsers.</p> <p>We welcome you to join us!</p> Build An Index With Pagedjs 2020-02-02T14:40:08Z https://pagedjs.org/posts/en/build-an-index-with-pagedjs/ <p>Download the script here: <a href="https://gitlab.coko.foundation/pagedjs/experiments/blob/master/book-index/js/createIndex.js">https://gitlab.coko.foundation/pagedjs/experiments/blob/master/book-index/js/createIndex.js</a></p> <h2 id="preparing-your-html" tabindex="-1">Preparing your HTML</h2> <p>In the simplest terms, a book index is simply a key to locating information contained in a book. The main idea of the book index is to help the reader find information quickly and easily. It is not a way to locate in the book all the paragraph where the word &quot;music&quot; appears but to locate the places in the book where the word music is &quot;revealing&quot; in relation to the content. In this way, create an index is a semantic work that cannot be done automatically.</p> <p>When you think your content is revelant and need to be in the index, simply add a span around the content:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><br> General definitions of<br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book-index<span class="token punctuation">"</span></span> <span class="token attr-name">data-book-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>music<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>music<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> include common<br> elements such as pitch, rhythm, dynamics, and the sonic qualities of timbre<br> and texture.<br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre> <p>Your span must contain at least two elements:</p> <ul> <li><strong>a class</strong>: this class is common to all index span elements of your document, you can name it as you wish</li> <li><strong>a data attribute</strong>: this data attribut must be named <code>data-book-index</code>, it indicates the word(s) that will appear in the index</li> <li>you can also add an id if you want but it's not required</li> </ul> <p>About the data attribute:</p> <ul> <li>all data attributes containing the same word will be combined in a single line in the index, so you can use the same data attribute several times in your document</li> <li>it is possible to use spaces, capital letters and dashes in the data attribute, like this for example: <code>data-book-index=&quot;Wolfgang Amadeus Mozart&quot;</code></li> <li>it is also possible to format the text with the <code>&lt;em&gt;</code> en <code>&lt;i&gt;</code> elements (only): <code>data-book-index=&quot;&lt;em&gt;String Quartet in C major&lt;/em&gt;&quot;</code></li> </ul> <p>Finally, you must add somewhere in your HTML an element in which the book index will be generated. It can be a section or a div but it must be indicated by an id (that you name as you wish):</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book-index<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre> <h2 id="use-the-script-with-paged.js" tabindex="-1">Use the script with paged.js</h2> <ol> <li>Add the <code>async</code> property to the paged.js script:</li> </ol> <ul> <li>if you use paged.js with npm: <code>&lt;script async src=&quot;http://localhost:9090/dist/paged.polyfill.js&quot;&gt;&lt;/script&gt;</code></li> <li>if you use the online script of paged.js: <code>&lt;script async src=&quot;http://unpkg.com/pagedjs/dist/paged.polyfill.js&quot;&gt;&lt;/script&gt;</code></li> </ul> <ol start="2"> <li>Add the book index script:</li> </ol> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js/createIndex.js<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre> <ol start="3"> <li>Call the book index scripthtml</li> </ol> <p>The book index need to be generated before that paged.js fragmented the content into pages. You need to the hook <code>before</code> to call the script.<br> Add this code in the <code>head</code> of you html document:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><br> window<span class="token punctuation">.</span>PagedConfig <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token function-variable function">before</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">spanClassIndex</span><span class="token operator">:</span> <span class="token string">"book-index"</span><span class="token punctuation">,</span><br> <span class="token literal-property property">indexElement</span><span class="token operator">:</span> <span class="token string">"#book-index"</span><span class="token punctuation">,</span><br> <span class="token literal-property property">alphabet</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre> <ol start="4"> <li>Use the print CSS properties in your stylesheet file to target the pages where the index elements appears:</li> </ol> <pre class="language-css"><code class="language-css"><span class="token selector">.link-page a::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">target-counter</span><span class="token punctuation">(</span><span class="token function">attr</span><span class="token punctuation">(</span>href<span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.link-page::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">", "</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.link-page:last-of-type::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.index-value::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">" – "</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <h2 id="configuring-the-script" tabindex="-1">Configuring the script</h2> <ul> <li><code>spanClassIndex</code>: define the id element where the toc list will be create</li> <li><code>indexElement</code>: define the id element where the toc list will be create</li> <li><code>alphabet</code>: choose if you want the alphabetical elements (<code>true</code>) or not (<code>false</code>)</li> </ul> <h2 id="styling-the-book-index" tabindex="-1">Styling the book index</h2> <p>The script generates a list with items you can style. Here is an example of a book index generated:</p> <figure> <img src="https://pagedjs.org/images/example-index.png" alt="Exemple of a generated book index"></figure> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-generated<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-alphabet-element<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alphabet-element-A<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>A<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-list-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Apple<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index-value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Apple<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>links-pages<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-23<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-list-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Apricot<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index-value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Apricot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>links-pages<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-15<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-35<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-list-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Avocado<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index-value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Avocado<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>links-pages<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-19<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-alphabet-element<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alphabet-element-B<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>B<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-list-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Banana<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index-value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Banana<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>links-pages<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-38<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-12<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-list-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Blackberry<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index-value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Blackberry<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>links-pages<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-17<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-24<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-alphabet-element<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alphabet-element-C<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>C<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-list-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Cherry<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index-value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Cherry<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>links-pages<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-32<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-27<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list-index-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-list-index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Coconut<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index-value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Coconut<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>links-pages<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-41<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-page<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#book-index-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre> <p>An example of CSS to styling the book index:</p> <figure> <img src="https://pagedjs.org/images/example-index-styled.png" alt="Exemple of a generated and styled book index"></figure> <pre class="language-css"><code class="language-css"><span class="token selector">#list-index-generated</span> <span class="token punctuation">{</span><br> <span class="token property">list-style-type</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.list-alphabet-element</span> <span class="token punctuation">{</span><br> <span class="token property">font-weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span><br> <span class="token property">padding-top</span><span class="token punctuation">:</span> 18px<span class="token punctuation">;</span><br> <span class="token property">padding-bottom</span><span class="token punctuation">:</span> 9px<span class="token punctuation">;</span><br> <span class="token property">font-family</span><span class="token punctuation">:</span> Arial<span class="token punctuation">,</span> Helvetica<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.index-value</span> <span class="token punctuation">{</span><br> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span><br> <span class="token property">min-width</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token selector">.index-value:first-letter</span> <span class="token punctuation">{</span><br> <span class="token property">text-transform</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><span class="token selector">.index-value::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">"none"</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">.link-page a</span> <span class="token punctuation">{</span><br> <span class="token property">text-decoration</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br> <span class="token property">color</span><span class="token punctuation">:</span> currentColor<span class="token punctuation">;</span><br> <span class="token property">font-family</span><span class="token punctuation">:</span> Arial<span class="token punctuation">,</span> Helvetica<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span><br> <span class="token property">font-size</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> Paged Media approaches : page floats 2020-02-01T21:24:56Z https://pagedjs.org/posts/en/paged-media-approaches-:-page-floats/ <p>Layout is the operation of positioning and styling elements of content in a given space. It aims to position the content (text, images, notes…) in a hierarchical and harmonious way (balancing the zones, colors and spaces, contrasts), in order to facilitate display and the flow of reading.</p> <p>Layout is more complex than the flow of content from one page to the next with appropriate elements of stylization. Each page must be balanced and provide for pleasant reading. To achieve this, we need to position elements in relation to the flow of text but also in relation to the page as well. Elements will have text wrapped around them to manage a pleasing allocation of white space and avoid creating widows and orphans.</p> <p>In CSS specifications, the float property is very interesting. The property indicates that an element is to be removed from the normal flow and instead be placed into a different place – currently, on the right or left side of its container. Text and other inline elements will then surround the floated element.</p> <p>In its simplest use, the float property can be used to wrap text around images. This property can take four values: <code>left | right | inherit | none.</code></p> <p>New properties (<code>float-reference</code>, <code>float-defer</code>) and values (for <code>float</code> and <code>clear</code> properties) have recently been proposed in the W3C working draft <a href="https://www.w3.org/TR/css-page-floats-3/">CSS Page Floats</a>. These properties add further ways of refining layouts and that’s what we are going to look at in this post. We also propose additional new extension values, based on what has already been proposed in proprietary tools such as Vivliostyle, Prince, PDFReactor and AntennaHouse.</p> <blockquote> <p>Paged.js is not yet supporting page-float, this article is there to help define the implementation and the future work.</p> </blockquote> <h1 id="float-reference-and-float-properties" tabindex="-1">Float reference and float properties</h1> <p>The float specification first needs to be established in reference to some default value or position. e.g. <em>“The entity to which the float is aligned initially before float placement takes place”</em> (<a href="https://www.w3.org/TR/css-page-floats-3/#terms">CSS Page Floats</a>).</p> <p>To do this, we need two properties:</p> <ul> <li><code>float-reference</code> allows the definition of a specific entity as the reference to which the element is moving. The float reference can be the float anchor’s line box, column, region or page; and</li> <li><code>float</code> is used to specify where the element will move in relation to this new reference.</li> </ul> <p>A simple example will make this clearer. In this example, initially, a figure is positioned around the middle of the page. We want to move the image to the top of the page. For this, we define the page as our float reference and we use the values <code>top</code> as following :</p> <pre class="language-css"><code class="language-css"><span class="token selector">figure</span> <span class="token punctuation">{</span><br><span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><br><span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br><span class="token property">float</span><span class="token punctuation">:</span> top<br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/article-figure-01.png"></figure> <h2 id="the-float-property-(w3c-specifications)" tabindex="-1">The float property (W3C specifications)</h2> <p>For the float property, the <a href="https://www.w3.org/TR/css-page-floats-3/#float-property">W3C draft specifications</a> propose the following values : <code>block-start | block-end | inline-start | inline-end | snap-block | snap-inline | left | right | top | bottom | none</code></p> <p>There are two types of values that I separate into two categories I call “floats XY” and “floats AB”.</p> <p><strong>Floats XY</strong></p> <p><code>left | right | top | bottom</code></p> <p>These values are interpreted relative to the page, independently of writing mode. Their physical directions correspond to the x-axis (horizontal dimension) and y-axis (vertical dimension) of the page.</p> <p><strong>Floats AB</strong></p> <p><code>block-start | block-end | inline-start | inline-end | snap-block | snap-inline</code></p> <p>These values are interpreted relative to the flow of content. There are abstract directional and dimensional calculated directly from the values of the writing-mode and direction properties.</p> <p>These flow-relative directions, <code>block-start | block-end | inline-start | inline-end</code>, are defined in the W3C recommendation <a href="https://www.w3.org/TR/css-writing-modes-3/#logical-directions">CSS Writing Modes Level 3</a> as follows:</p> <ul> <li><strong>block-start</strong> : “The side that comes earlier in the block flow direction, as determined by the writing-mode property: the physical top in horizontal-tb mode, the right in vertical-rl, and the left in vertical-lr.”</li> <li><strong>block-end</strong> : “The side opposite block-start.”</li> <li><strong>inline-start</strong> : “The side from which text of the inline base direction would start. For boxes with a used direction value of ltr, this means the line-left side. For boxes with a used direction value of rtl, this means the line-right side.”</li> <li><strong>inline-end</strong> : “The side opposite inline-start.”</li> </ul> <figure> <img src="https://pagedjs.org/images/article-figure-02.png"></figure> <!-- <img class="wp-image-698 " src="article-figure-02.png" alt="" srcset="article-figure-02.png 4167w, article-figure-02-300x227.png 300w, article-figure-02-768x581.png 768w, article-figure-02-1024x775.png 1024w, article-figure-02-1200x908.png 1200w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /> --> <p>So, the <code>block-start</code> float value gives a different result if it’s applied to elements contained in an entity with different writing-mode and direction properties. According to the specifications of the W3C working draft <a href="https://www.w3.org/TR/css-page-floats-3/">CSS Page Floats</a>, with the <code>block-start</code> float value, <em>“the element generates a box that is floated to the line-start outer edge of the float reference. Content flows on the line-end side of the box.”</em> This gives the following results:</p> <figure><img src="https://pagedjs.org/images/article-figure-03.png"></figure> <h2 id="avoiding-white-spaces" tabindex="-1">Avoiding white spaces</h2> <p>It often happens that an element ends up at the bottom of a page but is too big to fit within the page height, so the element is automatically pushed to the next page with a forced page break. This produces a gap, a white space, at the end of the previous page. It’s unsightly and, moreover, the reader might think that it means the end of a section. The float property can fix this problem.</p> <p>In the following example, the figure is already at the nearest edge, so it does not move. However, floats allow subsequent content to be displayed before the float and the white space can therefore be filled.</p> <figure> <img src="https://pagedjs.org/images/article-figure-04.png"></figure> <p>Note that in Prince, the proprietary optional modifier <code>unless-fit</code> is to be used in combination with other float instructions, and is conditional: the element is only floated if it would otherwise cause a page.</p> <p>element {<br> width: 100%;<br> float: top unless-fit<br> }</p> <h2 id="the-snap-block-value" tabindex="-1">The snap-block value</h2> <p>The <code>snap-block(&lt;length&gt; [, start | end | near ]?)</code> value and the <code>snap-inline(&lt;lengtht&gt; [, start | end | near ]?)</code> values specify than an element floats to the start or the end of the block if it naturally appears within a certain distance from either one.</p> <p>The length value specifies the reach of the snap function, e.g. the maximum distance from the start/end that an element must be within in order to be floated.</p> <p><em>“The length value specifies the distance from both the start and the end, two length values specify the distance from the start and end, respectively. The optional keyword value specifies where the element is floated: start, end, or the nearest of the two. The initial value is near. If near is in effect and the element is within the specified distance both from the start and the end, end wins.”</em> (W3C specifications)</p> <p>In this example the first element is affected, but not the second :</p> <p>element {<br> float-reference: page;<br> float: snap-block(2em near)<br> }</p> <figure> <img src="https://pagedjs.org/images/article-figure-05.png"></figure> <p>An element with the <code>snap-block()</code> value is considered to be a float even if the element does not appear within the specified distance. In this case, the element floats at the start / end line, but not at the start, nor at end of the block.</p> <figure> <img src="https://pagedjs.org/images/article-figure-06.png"></figure> <p>The <code>snap-block</code> and the <code>snap-inline</code> values correspond respectively to <code>snap-block(2em, near)</code> and <code>snap-inline(2em, near)</code>. It can be very useful to apply this float property to move an element to the top of the next page unless it fits on the current page without causing a break and leaving a gap, or without causing a widow or orphans.</p> <h1 id="extensions-proposals-for-pagedmedia-specs" tabindex="-1">Extensions proposals for pagedmedia specs</h1> <p>Although the W3C draft extends the possibilities for float values, they are still limited and some layouts are still not possible. In this part, I want to propose new extension values, sometimes based on what has already been proposed by some proprietary tools.</p> <h2 id="combinations-of-xy-directions" tabindex="-1">Combinations of XY directions</h2> <p>In the W3C draft, there is currently no way to float into a combination of directions (top right, right top, left bottom, bottom left, etc.) but it’s possible in Antenna House. For example, with <code>float: bottom left</code>, the element goes to the left bottom corner of the page. It’s a very interesting extension which allows more possibilities for layout.</p> <figure> <img src="https://pagedjs.org/images/article-figure-07.png"></figure> <h2 id="inside-and-outside-values" tabindex="-1">Inside and outside values</h2> <p>The values <code>inside</code> and <code>outside</code> are very useful in print because we often have to deal with left-facing and right-facing pages, together forming a spread. These values can be found in Prince or AntennaHouse and are interpreted relative to the page (floats XY), moving the elements respectively to the inside or outside of a spread:</p> <ul> <li>with the <code>inside</code> float value, an element can be floated at the left side on a right page and at the right side on a left page.</li> <li>with the <code>outside</code> float value, an element can be floated at the right side on a right page and at the left side on a left page.</li> </ul> <figure> <img src="https://pagedjs.org/images/article-figure-08-2.png"></figure> <h2 id="after-and-before" tabindex="-1">After and before</h2> <p>The values <code>after</code> and <code>before</code> are a new proposal which can be added to the list of floats interpreted relative to the flow of content (floats AB). They indicate that the content flows respectively on the block-start and the block-end side of the box. These values can be used in combination with the other “float AB” values to force the side of the content flow.</p> <figure> <img src="https://pagedjs.org/images/article-figure-09.png"></figure> <h4 id="update-(7%2F04%2F2018)" tabindex="-1">UPDATE (7/04/2018)</h4> <p>Shinyu Murakami (Vivliostyle) noted <a href="https://www.pagedmedia.org/page-floats/#comment-925">in a comment</a> of this article that <code>after</code> and <code>before</code> keywords were used in the W3C’s old logical (flow relative) direction terminology (W3C XSL-FO). <code>inline-start</code> and <code>inline-end</code> would probably be a better choice of keywords and fit closer the new W3C logic. We will adopt this terminology for the future. In the example above <code>block-start after</code> is transformed into <code>block-start inline-end</code>. The following demo has been updated.</p> <h2 id="need-to-extend-the-float-property" tabindex="-1">Need to extend the float property</h2> <p>In summary, if we take all the proposals that have just been detailed in this part, we can propose a global syntax for the float property:</p> <p><code>float: none | [&lt;float-x&gt; || &lt;float-y&gt;] || [&lt;float-a&gt; || &lt;float-b&gt;]</code></p> <p>with :</p> <ul> <li><code>&lt;float-y&gt; = top | bottom</code></li> <li><code>&lt;float-x&gt; = left | right | inside | outside</code></li> <li><code>&lt;float-a&gt; = block-start | block-end | inline-start | inline-end | snap-block(&lt;length&gt; [, start | end | near ]?) | snap-inline(&lt;length&gt; [, start | end | near ]?)</code></li> <li><code>&lt;float-b&gt; = before | after</code></li> </ul> <p>I have made a little demonstrator to show all the possibilities of this proposal with the application of these additional different kinds of floats: <a href="http://demos.pagedmedia.org/page-floats/">http://demos.pagedmedia.org/page-floats/</a></p> <img class="alignnone wp-image-696 " src="https://pagedjs.org/images/Capture-d%E2%80%99e%CC%81cran-2018-04-07-a%CC%80-14.29.04-1.png" alt="" srcset="https://pagedjs.org/posts/en/paged-media-approaches-:-page-floats/Capture-d%E2%80%99e%CC%81cran-2018-04-07-a%CC%80-14.29.04-1.png 2428w, https://pagedjs.org/posts/en/paged-media-approaches-:-page-floats/Capture-d%E2%80%99e%CC%81cran-2018-04-07-a%CC%80-14.29.04-1-300x208.png 300w, https://pagedjs.org/posts/en/paged-media-approaches-:-page-floats/Capture-d%E2%80%99e%CC%81cran-2018-04-07-a%CC%80-14.29.04-1-768x532.png 768w, https://pagedjs.org/posts/en/paged-media-approaches-:-page-floats/Capture-d%E2%80%99e%CC%81cran-2018-04-07-a%CC%80-14.29.04-1-1024x709.png 1024w, https://pagedjs.org/posts/en/paged-media-approaches-:-page-floats/Capture-d%E2%80%99e%CC%81cran-2018-04-07-a%CC%80-14.29.04-1-1200x831.png 1200w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px"> <h1 id="multicolumn-layout" tabindex="-1">Multicolumn layout</h1> <p>In multicolumn layouts, the float-reference property <code>float-reference: column</code> can be used. The floated elements will be placed according to the column which contains the float anchor, e.g. the point in the flow where the floated element would have appeared had it not been a float and instead had been an empty inline element with no margins, borders or padding.</p> <p>It’s still possible to use <code>float-reference: page</code> in multicolumn layouts. In this case, the same element with the same float value will be placed differently according to its float reference.</p> <figure> <img src="https://pagedjs.org/images/article-figure-10.png"></figure> <h2 id="column-span" tabindex="-1">Column span</h2> <p>The <code>column-span</code> property allows an element to span all columns when the value of the property is <code>all</code>. An element that spans more than one column is called a spanning element. This is useful for titles which break the flow of the columns and span several columns.</p> <p>Generally, in the tools explored for this article, an integer value is added for specifying how many columns an element should span across. This possibility is not available for now in the current draft of W3C but it’s very useful in combination with float properties for creating layouts such as those used in newspaper formats.</p> <pre class="language-css"><code class="language-css"> <span class="token selector">body</span> <span class="token punctuation">{</span><br> <span class="token property">column-count</span><span class="token punctuation">:</span> 3<br> <span class="token punctuation">}</span><br> <span class="token selector">img</span> <span class="token punctuation">{</span><br> <span class="token property">column-span</span><span class="token punctuation">:</span> 2<br> <span class="token property">float-reference</span><span class="token punctuation">:</span> column<br> <span class="token property">float</span><span class="token punctuation">:</span> top<br> <span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/article-figure-11.png"></figure> <h1 id="clear-property" tabindex="-1">Clear property</h1> <p>The clear property can be used to prevent stacking of floats. The possible values are the same as the float property, only the <code>snap-block()</code> and <code>snap-inline()</code> values are not available.</p> <p>The clear property indicates whether an element can be located next to floating elements that precede it (according to the direction indicated by the clear value) or if it needs to be moved in the next float reference container.</p> <p>With the code that follows, a figure can’t have another figure below it the same page. If another figure has its float anchor in the same page, this figure will appear in the next page when rendering.</p> <pre class="language-css"><code class="language-css"><span class="token selector">figure</span> <span class="token punctuation">{</span><br> <span class="token property">float-refrence</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br> <span class="token property">float</span><span class="token punctuation">:</span> bottom left<span class="token punctuation">;</span><br> <span class="token property">clear</span><span class="token punctuation">:</span> bottom<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/article-figure-12.png"></figure> <h1 id="float-defer-property" tabindex="-1">float-defer property</h1> <p>With the <code>float-defer</code> property, a floated element can be deferred to a subsequent fragmentation container. This property works with an integer value or with the keyword <code>last</code>: <em>“This property specifies whether the initial float reference of a page float is the fragmentation container in which the</em> float <em>anchor is placed after previous page floats have been placed, or in another one.”</em> (<a href="https://www.w3.org/TR/css-page-floats-3/#float-defer-property">W3C specifications</a>)</p> <p>An “n” positive integer value indicates that the element is deferring to the Nth fragmentation container of the “fragmentation flow” after the float anchor is initially placed (after all previous page floats have been placed within the given fragmentation context).</p> <p>An “n” negative integer value indicates that the element is deferring to the Nth fragmentation container of the “fragmentation flow” counting backward from the end. If the float reference of the deferring element is the page, the count starts on the last page of the flow section of the named page where the initial float anchor appeared. If the float reference of the deferring element is the column, the count starts on the last page column of the page where the initial float anchor appeared.</p> <pre class="language-css"><code class="language-css"><span class="token selector">figure</span> <span class="token punctuation">{</span><br> <span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br> <span class="token property">float</span><span class="token punctuation">:</span> top<span class="token punctuation">;</span><br> <span class="token property">float-defer</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/article-figures-13.png"></figure> <pre class="language-css"><code class="language-css"><span class="token selector">figure</span> <span class="token punctuation">{</span><br> <span class="token property">float-reference</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span><br> <span class="token property">float</span><span class="token punctuation">:</span> top<span class="token punctuation">;</span><br> <span class="token property">float-defer</span><span class="token punctuation">:</span> -2<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/article-figures-14.png"></figure> <p>These properties don’t work on any of the tools tested. However, in Prince and Antenna House, the <code>next</code> value is added to the <code>float</code> property: the floated element is placed on the next fragmentation container from its source location.</p> <h1 id="in-conclusion" tabindex="-1">In conclusion</h1> <p>The large number of values proposed by the W3C Working Draft <a href="https://www.w3.org/TR/css-page-floats-3/">CSS Page Floats</a> makes it possible, through the combination of properties, to imagine a large number of use cases and therefore to start expressing rich layouts.</p> <p>The implementation of this specification depends on the tool, but overall they are rather limited.</p> <ul> <li><strong>Browsers</strong> haven’t implemented anything.</li> <li><strong>Prince</strong> and <strong>Antenna House</strong> have their own proprietary values for the <code>float</code> properties, including some that run across those of the W3C specifications.</li> <li><strong>Vivliostyle</strong> have implemented <code>float-reference</code> and <code>float</code> properties very well. Johannes Wilm, the specification’s editor, is a member of the Vivliostyle Project Community</li> <li><code>clear</code> and <code>float-defer</code> are yet not implemented anywhere.</li> </ul> <p>The <a href="https://www.w3.org/TR/css-page-floats-3/">CSS Page Floats</a> specifications and the extensions proposed in this post are good candidates for increasing opportunities for the PagedMedia initiative. This would be interesting not only for the placement figures but also for augmented uses such as the two following examples on which I end this post.</p> <h2 id="full-page-image" tabindex="-1">Full page image</h2> <pre class="language-css"><code class="language-css"><span class="token selector">figure .full-page</span> <span class="token punctuation">{</span><br> <span class="token property">height</span><span class="token punctuation">:</span> 8in<span class="token punctuation">;</span> <span class="token comment">/* height of the page */</span><br> <span class="token property">float</span><span class="token punctuation">:</span> top<span class="token punctuation">;</span><br> <span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span><br> <span class="token property">top</span><span class="token punctuation">:</span> -0.8in<span class="token punctuation">;</span> <span class="token comment">/* margin top of the page */</span><br> <span class="token property">left</span><span class="token punctuation">:</span> -0.8in<span class="token punctuation">;</span> <span class="token comment">/* left margin of the page */</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/article-figures15.png"></figure> <h2 id="inserts-in-margins" tabindex="-1">Inserts in margins</h2> <pre class="language-css"><code class="language-css"><span class="token selector">.inserts</span> <span class="token punctuation">{</span><br> <span class="token property">width</span><span class="token punctuation">:</span> 30mm<span class="token punctuation">;</span><br> <span class="token property">margin-outside</span><span class="token punctuation">:</span> -38mm<span class="token punctuation">;</span><br> <span class="token property">float-reference</span><span class="token punctuation">:</span> page<span class="token punctuation">;</span><br> <span class="token property">float</span><span class="token punctuation">:</span> top outside<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <figure> <img src="https://pagedjs.org/images/article-figures16.png"></figure> Build a Table of Contents from your HTML 2020-01-01T14:56:54Z https://pagedjs.org/posts/en/build-a-table-of-contents-from-your-html/ <p>In this part of the doc, we'll show you how to build a table of contents using a custom script and the css function <code>target-counter()</code> for the <code>content</code> property.</p> <h2 id="build-the-table-of-contents-from-your-html" tabindex="-1">Build the table of contents from your html</h2> <p>In HTML, a table of contents is a <code>&lt;nav&gt;</code> elements that contain a list of the reveleant titles of your document with a link to the unique identifier of each. This part can be done with your own tool/generator but here is an exemple of a script to generate a table of contents in vanilla javascript:</p> <pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">createToc</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> content <span class="token operator">=</span> config<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br> <span class="token keyword">const</span> tocElement <span class="token operator">=</span> config<span class="token punctuation">.</span>tocElement<span class="token punctuation">;</span><br> <span class="token keyword">const</span> titleElements <span class="token operator">=</span> config<span class="token punctuation">.</span>titleElements<span class="token punctuation">;</span><br><br> <span class="token keyword">let</span> tocElementDiv <span class="token operator">=</span> content<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>tocElement<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">let</span> tocUl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"ul"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> tocUl<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">"list-toc-generated"</span><span class="token punctuation">;</span><br> tocElementDiv<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>tocUl<span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token comment">// add class to all title elements</span><br> <span class="token keyword">let</span> tocElementNbr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> titleElements<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> titleHierarchy <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span><br> <span class="token keyword">let</span> titleElement <span class="token operator">=</span> content<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span>titleElements<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> titleElement<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// add classes to the element</span><br> element<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"title-element"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> element<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"data-title-level"</span><span class="token punctuation">,</span> titleHierarchy<span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token comment">// add id if doesn't exist</span><br> tocElementNbr<span class="token operator">++</span><span class="token punctuation">;</span><br> idElement <span class="token operator">=</span> element<span class="token punctuation">.</span>id<span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>idElement <span class="token operator">==</span> <span class="token string">""</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> element<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">"title-element-"</span> <span class="token operator">+</span> tocElementNbr<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token keyword">let</span> newIdElement <span class="token operator">=</span> element<span class="token punctuation">.</span>id<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token comment">// create toc list</span><br> <span class="token keyword">let</span> tocElements <span class="token operator">=</span> content<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">".title-element"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tocElements<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> tocElement <span class="token operator">=</span> tocElements<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span><br><br> <span class="token keyword">let</span> tocNewLi <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"li"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token comment">// Add class for the hierarcy of toc</span><br> tocNewLi<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"toc-element"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> tocNewLi<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><br> <span class="token string">"toc-element-level-"</span> <span class="token operator">+</span> tocElement<span class="token punctuation">.</span>dataset<span class="token punctuation">.</span>titleLevel<br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token comment">// Keep class of title elements</span><br> <span class="token keyword">let</span> classTocElement <span class="token operator">=</span> tocElement<span class="token punctuation">.</span>classList<span class="token punctuation">;</span><br> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> n <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> n <span class="token operator">&lt;</span> classTocElement<span class="token punctuation">.</span>length<span class="token punctuation">;</span> n<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>classTocElement<span class="token punctuation">[</span>n<span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token string">"title-element"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> tocNewLi<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>classTocElement<span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><br> <span class="token comment">// Create the element</span><br> tocNewLi<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span><br> <span class="token string">'&lt;a href="#'</span> <span class="token operator">+</span> tocElement<span class="token punctuation">.</span>id <span class="token operator">+</span> <span class="token string">'">'</span> <span class="token operator">+</span> tocElement<span class="token punctuation">.</span>innerHTML <span class="token operator">+</span> <span class="token string">"&lt;/a>"</span><span class="token punctuation">;</span><br> tocUl<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>tocNewLi<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre> <p>Copy this script to a <code>.js</code> and link this file to your document.</p> <p>The table of contents need to be generated before paged.js fragment the content into pages. Therefore, you need to register the handler <code>beforeParsed()</code> and call the table of contents script inside.</p> <p>Add this code in the <code>head</code> of you html document after the call for paged.js script:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><br> <span class="token keyword">class</span> <span class="token class-name">handlers</span> <span class="token keyword">extends</span> <span class="token class-name">Paged<span class="token punctuation">.</span>Handler</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">chunker<span class="token punctuation">,</span> polisher<span class="token punctuation">,</span> caller</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">super</span><span class="token punctuation">(</span>chunker<span class="token punctuation">,</span> polisher<span class="token punctuation">,</span> caller<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">beforeParsed</span><span class="token punctuation">(</span><span class="token parameter">content</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">createToc</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">content</span><span class="token operator">:</span> content<span class="token punctuation">,</span><br> <span class="token literal-property property">tocElement</span><span class="token operator">:</span> <span class="token string">"#my-toc-content"</span><span class="token punctuation">,</span><br> <span class="token literal-property property">titleElements</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">".mw-content-ltr h2"</span><span class="token punctuation">,</span> <span class="token string">"h3"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br> Paged<span class="token punctuation">.</span><span class="token function">registerHandlers</span><span class="token punctuation">(</span>handlers<span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre> <h3 id="configuring-the-script" tabindex="-1">Configuring the script</h3> <p><code>tocElement</code>: define the id element where the toc list will be created</p> <p><code>titleElements</code>: array of the title element you want in the your table of contents. You can add as many as you want and the elements can be selected like any css, for example: <code>.title-1</code> or <code>.my-content h1</code></p> <h2 id="generate-page-numbers" tabindex="-1">Generate page numbers</h2> <p>Thanks to the previous script, your content is now structured using <code>id</code> for the heading, and the table of contents we created use hyperlinks to those <code>#id</code>:</p> <pre class="language-html"><code class="language-html"><span class="token comment">&lt;!-- the headings in the text--></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pre-digital_era<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-title-level</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> Pre-digital era<br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Content...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>digital_era<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title-element<span class="token punctuation">"</span></span> <span class="token attr-name">data-title-level</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> Digital era<br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Content...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre> <pre class="language-html"><code class="language-html"><span class="token comment">&lt;!-- the table of contents--></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>toc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#pre-digital_era<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Pre-digital era<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#digital_era<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Digital era<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre> <p>In the CSS, the <code>target-counter</code> property is used within <code>::before</code> and <code>::after</code> pseudo-elements, using the <code>content</code> property. It can be translated as: find the counter named <code>page</code> that appears where you find the element we’re targetting with the attribute <code>href</code>:</p> <pre class="language-css"><code class="language-css"><span class="token selector">#toc li a::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">target-counter</span><span class="token punctuation">(</span><span class="token function">attr</span><span class="token punctuation">(</span>href<span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token property">float</span><span class="token punctuation">:</span> right<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <h2 id="add-styles-to-the-table-of-contents" tabindex="-1">Add styles to the table of contents</h2> <p>If you need to add counters or leaders to your table of contents generated above, here is an exemple of CSS you can use:</p> <pre class="language-css"><code class="language-css"><span class="token comment">/* set the style for the list numbering to none */</span><br><span class="token selector">#list-toc-generated</span> <span class="token punctuation">{</span><br> <span class="token property">list-style</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element</span> <span class="token punctuation">{</span><br> <span class="token property">break-inside</span><span class="token punctuation">:</span> avoid<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element a::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">" p. "</span> <span class="token function">target-counter</span><span class="token punctuation">(</span><span class="token function">attr</span><span class="token punctuation">(</span>href<span class="token punctuation">)</span><span class="token punctuation">,</span> page<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token property">float</span><span class="token punctuation">:</span> right<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element-level-1</span> <span class="token punctuation">{</span><br> <span class="token property">margin-top</span><span class="token punctuation">:</span> 25px<span class="token punctuation">;</span><br> <span class="token property">font-weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element-level-2</span> <span class="token punctuation">{</span><br> <span class="token property">margin-left</span><span class="token punctuation">:</span> 25px<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token comment">/* counters */</span><br><br><span class="token selector">#list-toc-generated</span> <span class="token punctuation">{</span><br> <span class="token property">counter-reset</span><span class="token punctuation">:</span> counterTocLevel1<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element-level-1</span> <span class="token punctuation">{</span><br> <span class="token property">counter-increment</span><span class="token punctuation">:</span> counterTocLevel1<span class="token punctuation">;</span><br> <span class="token property">counter-reset</span><span class="token punctuation">:</span> counterTocLevel2<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element-level-1::before</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">counter</span><span class="token punctuation">(</span>counterTocLevel1<span class="token punctuation">)</span> <span class="token string">". "</span><span class="token punctuation">;</span><br> <span class="token property">padding-right</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element-level-2</span> <span class="token punctuation">{</span><br> <span class="token property">counter-increment</span><span class="token punctuation">:</span> counterTocLevel2<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element-level-2::before</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">counter</span><span class="token punctuation">(</span>counterTocLevel1<span class="token punctuation">)</span> <span class="token string">". "</span> <span class="token function">counter</span><span class="token punctuation">(</span>counterTocLevel2<span class="token punctuation">)</span> <span class="token string">". "</span><span class="token punctuation">;</span><br> <span class="token property">padding-right</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token comment">/* hack for leaders */</span><br><br><span class="token selector">#list-toc-generated</span> <span class="token punctuation">{</span><br> <span class="token property">overflow-x</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token comment">/* fake leading */</span><br><span class="token selector">#list-toc-generated .toc-element::after</span> <span class="token punctuation">{</span><br> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">".............................................."</span><br> <span class="token string">".............................................."</span><br> <span class="token string">".............................................."</span> <span class="token string">"........"</span><span class="token punctuation">;</span><br> <span class="token property">float</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span><br> <span class="token property">width</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br> <span class="token property">padding-left</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span><br> <span class="token property">letter-spacing</span><span class="token punctuation">:</span> 2px<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element</span> <span class="token punctuation">{</span><br> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element a::after</span> <span class="token punctuation">{</span><br> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span><br> <span class="token property">right</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br> <span class="token property">background-color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span><br> <span class="token property">padding-left</span><span class="token punctuation">:</span> 6px<span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token selector">#list-toc-generated .toc-element a</span> <span class="token punctuation">{</span><br> <span class="token property">right</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre> <p>And <em>voilà</em>!<br> All the files (scripts, CSS, HTML exemples) to create a table of contents are available on gitlab: <a href="https://gitlab.coko.foundation/pagedjs/experiments/tree/master/table-of-content">https://gitlab.coko.foundation/pagedjs/experiments/tree/master/table-of-content</a>.</p>