Open JulieBlanc opened 4 years ago
Thanks for your good work on notes. It's an important topic which has been neglected by the web. Hyperlinks have spoiled us, I think. Sidenotes are essential to producing good-looking textbooks other publications.
I like that you specify the note-area in CSS (and not try using HTML, like Regions did), that you base the solution on the @footnotes approach, and that the note-area can be shaped and positioned with the normal CSS properties.
The proposal is missing a feature which I think must be addressed. Figures often intrude into the margin area, and the corresponding caption is often placed in the margin area. Since the caption occupies the same space as the note area, I think it would be beneficial to coisider it a note. For example, consider this spread from a textbook:
The placement of the captions can be tricky, though, as figure may snap to the nearest edge; if the figure snaps to the top of the page, the caption will be displayed below the figure. And if the figure snaps to the bottom of the page, the caption should be displayed above. From a style sheet perspective, this is tricky to specify, but I think we must try, as the formatting is very common.
I also think the proposal could benefit from having more ways to align sidenotes in the note-area. An obvious first approach is to stack the sidenotes from the top. The second-most common alignment is baseline alignment with the natural position of the sidenote. This is handled with 'float-reference: line' in the proposal. This solution doens't seem intuitive to me -- 'float-reference' is use for shaping float and not for alignment. I've sketched a solution which accepts a number of keywords here:
https://books.idea.whatwg.org/#flowing-content-to-a-named-area:-'flow'
Moving a note to the bottom of the note-area is also common, as can be seen here:
Finally, the 'note-policy' is well-named property, but I miss a way to say: if the note doesn't fit, just delete it. But perhaps that's specified somewhere else?
This extensive issue is a draft specifications for notes creation and positioning in continuous and paged media.
This draft is based on:
note()
value, that you can use in the content property to declare elements as notes;element()
value to place the element removed from the flow (ie the note) in a specific place of the same document,@note-area
at-rule that can be used to display notes in a page;::note-area
pseudo-element to create end-notes for any block elements.Table of Contents
::note-call
pseudo element 4.5 The::note-marker
pseudo element 4.6 The ::note-callback pseudo element@footnote
special at-rule::note-area
pseudo element1. Types of notes
For now, the W3C specifications only allow the creation of footnotes, as described in the CSS Generated Content for Paged Media Module (css-gcpm-3). But we know that designers and editors like to be able like to make use of all kinds of notes. You can find some examples here: https://www.w3.org/XML/2015/02/footnote-examples/. To name a few:
2. Specifications W3C
A part of the CSS Generated Content for Paged Media Module (css-gcpm-3) is dedicated to footnotes. The first section defines the terms of the footnote objects. These definitions can be applied to all types of notes, thus we’ll keep the same terms but will while removing the prefix “foot”, for the rest of this issue discussion:
The specification also describes how to create footnotes in a page with the following code:
This code also creates the special footnote counter and special pseudo-elements for footnote calls (
::footnote-call
) and footnote markers (::footnote-marker
). The position, size and styles of the footnote area are defined by the@footnote
declaration. The specification does not set precise limits, only a couple of paragraphs and a lot of issues and unanswered questions. The advantage is that we can do many proposals without conflicting with the current specifications.In css-gcpm-3, there is this issue:
We agree that unsing double float declaration is complex. But a mechanism is needed to move the note element into a specific area of the page or the document. To do this, we can take inspiration from a mechanism already present in the draft of the paged media specifications, the running element: by adding the
position: running()
declaration, we can remove an element from the flow to reuse it in multiple places, perfect for the running heads of a book for example.For the notes, we’d like to propose a new way to create and place notes, based on new values (
notes()
andelement()
) for properties already in the CSS specifications (position
andcontent
).3. Proposal: pattern to create notes
3.1. Global pattern
Notes are always dependent on a principal flow, but they are out-of-flow elements, such as an aside. This is ancillary content that may be moved to the bottom of the page, to its margins, or to another section of the document. A note is created when the content is moved to a specific area of the document, leaving a reference indicator behind.
For all types of notes, we can see a pattern to build them:
3.2. Clarification about HTML elements
The W3C doesn't provide a dedicated way to tag notes in HTML. Some discussions in the mailing list of the W3C or whatwg, or in blog articles, suggest different ways but none of them seem to have unanimous agreement.
In use
In the meantime, there are two most commonly used methods of adding notes:
href
attrbute pointing to sections of a page with fragmented URLs. This mechanism provides some issues pointed out by Greg Lowney in terms of accessibility. This also poses problems with more complex layouts. If the notes elements are presented in a list, it becomes necessary to transform the DOM to place them in the manner of a side note, end notes or footnotes (both for continuous and/or paged media).<span>
elements directly in paragraphs to encapsulate note elements in the place where they appear. This is the method used in examples in the css-gcpm-3 draft.In unofficial specifications
David MacDonald and Shane McCarron propose specifics
<note>
,<notegroup>
and<refnote>
elements in some unofficial specifications. One part of the document presents uses cases and a lot of requirements that are very useful. However, we believe that many of the HTML syntaxes proposed in the document can be best achieved through CSS mechanisms.What we’d like to have
Therefore, we propose to use only one
note
element.A
note
element represents a note, e.g. a 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. Thenote
element must be placed where the note appears in the content flow. This is a new type of HTML element which has the following properties:<note>
and closing</note>
tags. Any content between those two tags is part of the content of the note.note
element can be the child of any grouping content element or heading element.note
element accepts other block or inline elements such as paragraphs, table, images, list, etc.note
element can be a child of anothernote
element.<note>
element accepts all the global attributes.<note>
element to read it when they want.The following example is a conforming HTML fragment:
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).
Until this element exists in HTML, a span element will be used with a class named “note” for illustrative purposes.
4. Create notes with CSS
A mechanism is needed to move the note element into a specific area of the page or of the document, and leaving a reference indicator in its place. To do this, we add the
note()
value to the position property and theelement()
value to the content property.4.1. The 'note()' value
The
note()
function removes the element (and associated::before
and::after
pseudo-elements) from the principal flow, and makes it available to place in a page margin-box, a page note-area@note-area
or a::note-area
pseudo element usingelement()
. The element inherits from its original position in the document, but is not rendered there, instead a::note-call
pseudo-element is created and inserted in the original position of the note. The elements keep their defined styles. A custom identifier is required:note(<custom-ident>)
. If there is noelement()
value corresponding to the custom identifier of thenote()
value, the elements are not removed from the flow and are shown as inlinenote
elements.4.2. The 'element()' value
To place the elements removed from the flow in a specific place on the document or page, we can use the function
element()
already present in the specifications and usable in acontent
property.A custom identifier is required (same as the corresponding
note()
function):element(<custom-ident>)
.The keyword
all-once
To make
element()
work withnote()
, a specific behaviour needs to be added that can be declared via an optional keyword all-once.With the keyword
all-once
, the value of all the assignment of the document or the page are used. ie - all the note elements (which have been removed from the normal flow vianote()
) are display in the new area where they're assigned. Each element fromnote()
value is displayed in the same order of the flow and has only one assignment in the document or in the page (the elements are not repeated). The value may be empty if there is no note element on the page.element() = string(<custom-ident>, all-once)
In addition to that, the
element()
function can be used not only in margin boxes but also in new page area@note-area
or a::note-area
pseudo-element.Example 1: notes in page note area
Example 2: notes in page margin box
Using the
element()
function, the margin-boxes can now receive the content of thenote
elements.The dimensions and (default) properties of a margin box works as described in CSS-page-3. The size of the note area does not affect the content page area.
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 is set in
@left-top
at-rule.ISSUE 1: In css-gcpm-3, the default value of the second argument of the
element()
function isfirst
. However, when notes are created from thenote()
function, this should be the valueall-once
by default. How do you indicate this?ISSUE 2: If the other arguments of the function
element()
are declared (first
,first-except
,last
,start
), what does that do for the note elements?4.3. The note counter
This section and follows contains some specifications of css-gcpm-3.
The note counter is a predefined counter associated with the note element. Its value is the number or symbol used to identify the note. This value is used in both the note call and the note marker. It should be incremented for each note.
The note counter, like other counters, may use any counter style. Notes often use a sequence of symbols.
The note counter can be reset on each page:
Or it can be reset per element:
Note that the value of the note counter should depend on the position of the note element in the document tree, not where it is eventually placed. A note element may sometimes be placed on the page after the note call, but the same counter value must be used for both.
4.4. The
::note-call
pseudo elementA
::note-call
pseudo-element is inserted in place of thenote
element when the latter is removed from the flow. By default, the content of this pseudo-element is the value of the note counter, styled as a superscripted number. It must act like an anchor.4.5 The
::note-marker
pseudo elementThe
::note-marker
pseudo-element represents the note element’s marker, the number or symbol that identifies each note. This pseudo-element behaves like a::marker
pseudo-element, as defined in [CSS3LIST]. It is placed at the beginning of the parent’s content, and is inline by default. The::note-marker
can be styled just as other::marker
elements can be. The default style should includelist-style-position: inside
, or be set as any other list.4.6. The ::note-callback pseudo element
The
::note-callback
pseudo-element represents the note element's call back, e.g. a navigation back from a note that returns to the correct associated::note-call
. It is placed at the end of the superior parent’s content, and is inline by default. By default, the content of this pseudo-element is the Leftwards Arrow with Hook Unicode Character (“↩” U+21A9). It must act like a link.5. Page note areas
The
@note-area
at-rule creates special page areas that can be used to display notes elements via theelement()
function. Those areas, called "page note areas", are created within the page context, which is the declaration block of the @page rule. This rule defines a box that, if used, will contain the corresponding note elements that appear on that page and move by generated content properties for notes. Since note areas are in the context page, notes boxes are contained in the content area of a page box.The
@note-area
may be following by a custom identifier.The properties of a note box are determined by properties declared in the
@note
rules. These properties can be used to define:If the content of a note area overflows from the box, it will go to the next page, in the same note area (see 6. Notes policy).
5.1. Positioning schemes of note area
Any of the CSS layout facilities can be used to create, position and size note areas: float, absolute positioning, grid, exclusion, etc.
CSS Page float add some values to the
float
property to positioning element in a page context and propose thefloat-reference
property to indicate the "reference container" for a floated element. We will make extensive use of these properties in the following examplesDefault values of properties for
@note-area
:Example 3
Using float on the page and negative margins can be helpful in creating note area half on merge, half on text content.
Example 4
Since a note area is a box, it's possible to layout the area itself (with columns for example).
5.2. Multiple notes areas in a page
There are already a lot of use cases in critical editions where you can find multiple kinds of notes (bibliographical references, explanations, etc.) The
@note-area
at-rules declaration make multiple notes easier by mixing multiple note areas in the same page context.Example 5
Example 6
In this example, we add a new value
line
to thefloat-reference
property. This allows creation of marginal notes, i.e., notes paced to one side of the text, with the first line at the same height of the flow that contains the note-call.ISSUE 3: This requires the creation of a new algorithm to avoid the overlapping of notes.
5.3. Notes for multi-column layout
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. This layout creates some issues:
CSS Page float proposes the
float-reference
property to indicate the "reference container" for a floated element. The valuecolumn
indicates that the float reference is the column in which the floated element is placed in a multi column environment.We can use this reference to indicate the 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 target by one
@note-area
rule only.Example 7
5.4. @footnote special at-rule
css-gcpm-3 define a special
@footnote
rule. This rule can be kept in this specification as a specific@note-area
with predefined positioning scheme. It behaves like a floated bottom page element. No positioning scheme designed by the user is taken into account in this@footnote
rule, and only one footnote box can be created on a page.Example 8
This would have the exact same behavior when using the following declarations:
6. The
::note-area
pseudo elementWe propose this specific pseudo-element to be able to create end notes for any block elements without having to create specific HTML markup. This pseudo-element can be use in both screen/continuous and paged media
The
::note-area
is a new kind of pseudo-element intended to receive generated content created fromnotes()
value. The only value authorised in thecontent
property of::note-area
is theelement()
function.::note-area
create a pseudo-element that is the last-child of the selected element or the penultimate if::after
pseudo-element is displayed. It’s a block level element by default.The
::note-area
will only receive the notes included in its primary parent (it won’t get all the notes from other elements), and will be displayed vianote()
andelement()
values.Example 9
The
::note-area
can be used to create end notes for allsection
elements.7. Notes policy
In paged media, it can happen at the end of the page that the last note overflows from the note area. As a general rule, overflow content can be moved to the next page in the note area or the margin box that corresponds to the previous one. However, rendering notes can be complex. Like the
footnote-policy
property in the css-gcpm-3, we need anote-policy
that gives authors some controls over the rendering. We propose to update the current specifications.The
note-policy
must be declared in the global context of the note area or the margin box.The values accepted in
note-policy
areauto
,line
orblock
.note-policy: auto
The user agent chooses how to render notes, and may place some of the note body on a later page than the note reference. A note body must never be placed on a page before the note reference.
If the entire note doesn't fit in the note area or the margin box, due to the lack of space, the user agent displays the note line by line. If the addition of a new line implies the disappearance in the page of the line of text containing the note call, the user agent stops the rendering of the note and passes the content of the remaining note in the corresponding note area on the next page. Note that the user agent must honor widow and orphans settings when doing this, and may need to apply
line
value on certain notes to do so.note-policy: line
If a given note body cannot be placed on the current page due to lack of space, the user agent introduces a forced page break before the line containing the note reference, so that both the reference and the note body end up on the next page. Note that the user agent must honor widow and orphans settings when doing this, and may need to insert the page break on an earlier line.
note-policy: block
Same for line, except that the forced page break is introduced before the paragraph that contains the note.
Et voilà! It's a long proposal, I hope we can work on it, we await your comments. :)
We also put down a post on the paged.js web site to explain our approach in a little bit less technical way: https://www.pagedjs.org/posts/2020-05-13-notes-about-notes/