Books often use sidenotes to hold notes and figures in the margin, next to the main flow. Prince now supports such sidenotes through simple extensions to the float
property, and we invite you to download and try formatting the code snippets in this guide. Prince is a HTML-to-PDF-via-CSS converter which offers advanced layout features so that you can create books from HTML.
To get started, we define a sidenote area
inside @page
section of the CSS stylesheet. In this example, we create a sidenote area on the right side of the flow:
html@page { @rightnote { width: 40vw } } aside { -prince-float: sidenote; background: beige; } <aside>Did you hear about... <aside><img ... <aside>Why don't scientists... <aside><img ...
In the above example, aside
elements are moved to the sidenote area (defined with @rightnote
) which is given a 40vw
width. You cannot set the height of the sidenote area (it always has the height of the main flow), but you can set other box-relasted properties, like padding
and background
.
There can be two sidenote areas on a page, one on the left and one on the right. Here they are given a width, and some padding to separate them from the main flow:
html@page { @leftnote { width: 30vw; padding-right: 1em; } @rightnote { width: 30vw; padding-left: 1em; } } aside { -prince-float: rightnote } figure { -prince-float: leftnote }
The sidenote area is referred to as rightnote
and leftnote
when you need to distinguish between them, otherwise the generic sidenote
will do.
By default, sidenotes appear near their anchoring points. But they can also be floated to the top or bottom of the sidenote area:
html@page { @leftnote { width: 30vw; } @rightnote { width: 30vw; } } aside { -prince-float: rightnote top } figure { -prince-float: leftnote bottom }
Sidenotes work well in multi-column environments where negative margins (which can be used to emulate sidenotes) will fail.
htmlbody { columns: 2 } .joke { -prince-float: sidenote; font-style: italic; }
Unlike footnotes, sidenotes are not automatically numbered. This is something that might be considererd for the fugure. Meanwhile, a small script can help us:
htmlbody { columns: 2 } .joke { -prince-float: sidenote; font-style: italic; } .joke::before { content: "[" counter(sn) "] "; } .snc { counter-increment: sn; content: "[" counter(sn) "] "; } <script type="text/javascript" src="https://css4.pub/2022/charms.js"></script> <body onload="addSidenoteMarks('span','snc')">
The script will look for span
elements, and create corresponding sidenote call elements, of class snc
.
The sidenote areas are conceptually similar to the footnote area, and all of them can be used on the same page:
html@page { @leftnote { width: 30vw; padding-right: 1em; } @rightnote { width: 30vw; padding-left: 1em; } @footnote { border-top: solid black thin; padding-top: 8pt; } } .fn { -prince-float: footnote } ::footnote-marker { content: "[" counter(footnote) "] " } .greek { -prince-float: leftnote } .greek::before { content: "[" counter(cg, lower-greek) "] " } .roman { -prince-float: rightnote } .roman::before { content: "[" counter(cr, lower-roman) "] " }
In the previous example, only the true footnotes have calls
in the main text. This is fixed with a small script:
html@page { @leftnote { width: 30vw; padding-right: 1em; } @rightnote { width: 30vw; padding-left: 1em; } @footnote { border-top: solid black thin; padding-top: 8pt; } } body { counter-reset: cr cg; } .fn { -prince-float: footnote } ::footnote-marker { content: "[" counter(footnote) "] " } .greek { -prince-float: leftnote } .greek::before { content: "[" counter(cg, lower-greek) "] " } .roman { -prince-float: rightnote } .roman::before { content: "[" counter(cr, lower-roman) "] " } .croman { counter-increment: cr; content: "[" counter(cr, lower-roman) "] "; } .cgreek { counter-increment: cg; content: "[" counter(cg, lower-greek) "] "; } <script type="text/javascript" src="https://css4.pub/2022/charms.js"></script> <body onload="addSidenoteMarks('.roman','croman'); addSidenoteMarks('.greek','cgreek')">
The float
property is a shorthand; the underlying individual properties can also be used:
html@page { @leftnote { width: 30vw; } @rightnote { width: 30vw; } } aside { -prince-float-reference: rightnote; -prince-float-placement: top; } figure { -prince-float-reference: leftnote; -prince-float-placement: bottom; }
The sidenote areas can have different widths and background colors on different pages. Also notes can be floated to the outside
and inside
sidenote areas:
html@page :left { @leftnote { width: 20vw; background: peachpuff; } @rightnote { width: 40vw; background: palegreen; } } @page :right { @leftnote { width: 25vw; background: honeydew; } @rightnote { width: 35vw; background: linen; } } @page:nth(3) { @leftnote { width: 40vw; background: khaki; } @rightnote { width: 10vw; background: lightcyan; } } .ref { -prince-float: top outsidenote } aside { -prince-float: insidenote }
Often, a wide figure will extend into the margin area. This can be expressed with the wide
, wide-left
and wide-right
keywords. In this example, the first three figures extend into both sidenote areas, while the last figure remains in the main flow.
html@page { @leftnote { width: 30vw; } @rightnote { width: 30vw; } } .w { -prince-float: wide } .wl { -prince-float: wide-left } .wr { -prince-float: wide-right } ... <figure class=w><img src=sinus.svg></figure> ... <figure class=wl><img src=sinus.svg></figure> ... <figure class=wr><img src=sinus.svg></figure> ... <figure><img src=sinus.svg></figure> ...
There are also wide-inside
and wide-outside
keywords:
html@page { @leftnote { width: 30vw; } @rightnote { width: 30vw; } } figure.sinus { -prince-float: wide-inside; } figure.tangent { -prince-float: wide-outside; }
Wide figures can also be combined with captions in the sidenote area:
html@page { @rightnote { width: 40vw } } figure { -prince-float-reference: wide; } figure figcaption { -prince-float-placement: inherit; -prince-float-reference: sidenote; background: beige; } .top { -prince-float-placement: top } .bottom { -prince-float-placement: bottom }
Notice how the figure caption is placed below the top figure and above the bottom figure. This due to wide
figures being laid out before other sidenotes.
Captions placed in the sidenote area must be connected with their figure. The order of the figcaption
and img
elements is relevant to achieve these common placements:
htmlfigcaption.align-top { -prince-float: sidenote align-top; } figcaption.align-bottom { -prince-float: sidenote align-bottom; } <figure> <figcaption class=align-top>A sine ... <img src=tangent.svg> </figure> <figure> <img src=tangent.svg> <figcaption class=align-bottom>A sine ... </figure>
The align-top
keyword means that the top of the sidenote will be aligned with the top of the box where it naturally appears. So float: sidenote align-top
in plain English is saying:
However, if more than one sidenote naturally appears on the same line, the sidenotes will be stacked in the content order, so all requests cannot be grated.
There is a corresponding align-bottom
keyword where the bottom of the sidenote is aligned with the top of the box where it naturally appears.
Aligning captions like you see in the image below requires a hack: the caption must be absolutely positioned within a wide figure element, and the width of the image and caption must be set manually.
html@page { @rightnote { width: 40vw } } figure { position: relative; } figure img { width: 65% } figure figcaption { width: 35%; position: absolute; right: 0; background: beige; box-sizing: border-box; } figure.top { -prince-float: top wide } figure.top figcaption { bottom: 0 } figure.bottom { -prince-float: bottom wide } figure.bottom figcaption { top: 0 }
To achieve the alignment from the previous example on pages with different left/right sidenote areas, a small script is needed for top-floating figures.
html@page:left { @leftnote { width: 40vw } } @page:right { @rightnote { width: 40vw } } figure.bottom { -prince-float: bottom wide } figure.bottom img { width: 65%; float: inside } figure.bottom figcaption { width: 35%; float: outside } figure.top { -prince-float: top wide } figure.top img { display: inline-block; width: 60%; float: inside } figure.top figcaption { display: inline-block; width: 30%; float: outside } <script type="text/javascript" src="https://css4.pub/2022/charms.js"></script> <body onload="alignCaptions('figure.top figcaption')">