This is an export backend for Org mode that exports buffers to HTML that is compatible with Tufte CSS.
Version 4.x alters some of the internals considerably from the 3.x version. Notably some configuration options have changed. See below for details.
- Some care is taken to ensure that the IDs of the generated HTML elements (e.g., footnote references) are reproducible. In case the IDs vary across builds, it’s a bug. Versions 4.1.x were supposed to implement this, but those releases were botched.
- Altering variables
org-html-checkbox-type
andorg-html-divs
no longer has any effect. To provide default values for the corresponding options, use variablesorg-tufte-html-checkbox-type
andorg-tufte-html-sections
respectively. The properties are still called:html-checkbox-type
and:html-divs
, however. - Similarly,
HTML_DOCTYPE
(as well, variableorg-html-doctype
and property:html-doctype
) andHTML_CONTAINER
(as well, variableorg-html-container-element
and property:html-container
) keywords andhtml5-fancy
option (as well, variableorg-html-html5-fancy
and property:html-html5-fancy
) are disabled. Altering these values from the defaults is not supported. - The
tufte-html
backend definition makes explicit the options that it overrides compared to thehtml
backend. - New command
org-tufte-convert-region-to-html
added. - Invoking
org-export-string-as
now works (#22). - Loading
ox-tufte
now advisesorg-export-as
. For advanced uses, the depth of the installed advice is user-configurable viasetopt
(seeorg-tufte-export-as-advice-depth
).
Tufte CSS has visually appealing defaults for webpages and supports (among other
things) margin and side notes. Unfortunately, Tufte CSS makes a number of
demands of the HTML structure. This is a pity, because the HTML generated by
ox-html
breaks some of those assumptions (of tufte-css
). Using ox-tufte
you can avail the features of tufte-css
when exporting an org-mode file to
HTML. Since version 2+, the design goal of ox-tufte
has been to minimally
change the HTML structure generated by ox-html
(with additional CSS as needed)
to get behaviour that is equivalent to tufte-css
.
ox-tufte
tries very hard to not introduce additional constraints (over and
above those imposed by ox-html
and tufte-css
) for users. In fact, work on
ox-tufte
version 2 began after noticing that:
ox-tufte
was broken and didn’t faithfully reproduce thetufte-css
experience.- org-tufte made additional assumptions and was too opinionated. E.g.,
ox-tufte
is still a work-in-progress, but it is being used by at least one
blog in “production”. Please open an issue if you discover any bugs!
Ox-tufte is compatible and tested with
tufte-css
v1.8.0org-mode
>= 9.5emacs
>= 27.1
It’s worth noting that Emacs 27.1 comes with Org version 9.3 (Org version 9.5 comes with Emacs 28.1), however, it can be updated via Emacs’s “package menu” (M-x list-packages).
Please open issues if you discover any incompatibility!
You can install ox-tufte using MELPA:
(add-to-list 'package-archives
'("melpa" . "http://melpa.org/packages/") t)
(package-refresh-contents)
(package-install 'ox-tufte)
And then in your init.el
(or equivalent):
(require 'ox-tufte)
It’s important that you download tufte css (v1.8.0) and place it on your server (with the fonts).
The recommended way to use ox-tufte
is with the default style provided by
ox-html. Include tufte.css
followed by src/ox-tufte.css
(strictly in that
order) in your org-mode document. This can be done by setting the :html-head
option for ox-html. This can be done in elisp, or done in the specific
org-mode document by adding a header such as:
#+HTML_HEAD: <link rel="stylesheet" href="/path/to/tufte.css" type="text/css" />
#+HTML_HEAD: <link rel="stylesheet" href="/path/to/ox-tufte.css" type="text/css" />
For usage, when exporting simply select “Tufte HTML” instead of regular HTML
export from the export menu (C-c C-e
).
ox-tufte supports most of the features from tufte-css, some in different ways than expected, and some extensions.
Tufte-css concept | Org-mode syntax for tufte-css concept | ox-tufte extension |
---|---|---|
Sections and Headings | Sections and Headings | |
Sidenotes | Footnotes | |
Margin-notes | inline babel call to “marginnote” block | block margin-notes via “marginnote” special-block |
Epigraphs | Quote block | |
iframe wrapper | “figure” org-mode special-block | |
Code | Source block | |
ImageQuilts | single image or images in”figure” special-block |
<<footnotes>>Org-mode footnotes become numbered Sidenotes from the tufte
spec. The only limitation (inherited from tufte-css
) is that a footnote can no
longer include another footnote within.
<<marginnotes-inline>>Since, Org-mode doesn’t yet support syntax for inline special blocks (though it’s being discussed and may be implemented in the near future), there are multiple ways to express inline margin-notes (i.e., margin-notes that can include HTML phrasing content). Inline margin-notes are implemented in their most feature-full incarnation as an inline babel call, specifically, to the “marginnote” block defined below.
If the only content of an inline margin-note is a link to an image, the
generated HTML will be malformed. Use the zero width space escape character to
communicate to the export process that the rendered image is to be contained
within a paragraph. If you need to enforce a line break within the margin-note,
use \\
at the end of a line as follows:
This is some regular text call_marginnote("this will be a margin note") and some
more text call_marginnote("another margin note.\\
new line in second margin note.").
An alternative syntax of an inline margin-note as a macro is also provided with the following additional (wrt the inline babel call syntax) caveats:
- macro invocations are not permitted in this syntax
- commas need to be escaped with a backslash (
\
) - line breaks can be enforced by adding an unescaped comma
This is some regular text {{{marginnote(this will be a margin note)}}} and some
more text {{{marginnote(another margin note.,new line in second margin
note.)}}}.
If, however, you only need an inline margin-note with some text without requiring specific control over line breaks or insertion of links or images (but still allowing for macro and babel call invocation), the margin-note-as-a-link syntax might be preferable.
- The margin note number is optional and either `mn:1` or `mn:` as below would work:
This is some regular text [[mn:1][this will be a margin note. while links aren't
supported, commas don't need escaping.]] and some more text [[mn:][another margin note]].
The reason for not being able to insert links (or images) using this syntax is an org syntax limitation.
There is also support for “block” margin-notes, which are margin-notes that can
contain “block” elements (HTML spec flow content) such as paragraphs, lists,
tables etc. These are defined using an org-mode “marginnote” special-block
(i.e., within #+begin_marginnote
and #+end_marginnote
, or within
#+BEGIN_marginnote
and #+END_marginnote
).
#+begin_marginnote
This is a block level margin-note.
- item 1
- item 2
#+end_marginnote
The block marginnote is displayed to the right side of the paragraph following
it. In case a block margin-note is needed in the zeroth section (i.e., before
the first heading in an org document), it needs to be wrapped within
#+begin_zeroth-section
and #+end_zeroth-section
as follows:
#+begin_zeroth-section
#+begin_marginnote
This is a block level margin-note.
- item 1
- item 2
#+end_marginnote
#+end_zeroth-section
- Anything within
#+begin_epigraph
and#+end_epigraph
becomes an epigraph (which is a collection of one or more quoted blocks). For example:#+begin_epigraph #+name: quote-1 #+caption: Richard P. Feynman, @@html:<cite>“What Do You Care What Other People Think?”</cite>@@ #+begin_quote For a successful technology, reality must take precedence over public relations, for Nature cannot be fooled. #+end_quote #+name: quote-2 #+caption: Henri Matisse, @@html:<cite>Henri Matisse Dessins: thèmes et variations</cite>@@ (Paris, 1943), 37 #+begin_quote I do not paint things, I paint only the differences between things. #+end_quote #+end_epigraph
ox-tufte
also adds support for#+CAPTION
on org-modequote
andverse
blocks.
<<code>>Code
ox-tufte
uses ox-html
to export code fragments to HTML (without any
alteration). ox-html
and =htmlize= allow one to customize the syntax
highlighting of the exported code blocks. An Emacs color theme that is visually
consistent with tufte-css
is the =plan9-theme= which can be installed from
Melpa via something like:
(add-to-list 'package-archives
'("melpa" . "http://melpa.org/packages/") t)
(package-refresh-contents)
(package-install 'plan9-theme)
And then in your init.el
or equivalent, load it using:
src_elisp{(load-theme ‘plan9 t)}.
To use tufte-css
’s iframe-wrapper
class, one can do something like below:
#+ATTR_HTML: :class iframe-wrapper
#+begin_figure
@@html:<iframe width="853" height="480" src="https://www.youtube.com/embed/YslQ2625TR4" frameborder="0" allowfullscreen></iframe>@@
#+end_figure
To have fullwidth figures:
#+ATTR_HTML: :class fullwidth
#+begin_figure
#+CAPTION: Edward Tufte’s English translation of the Napoleon’s March data visualization. From Beautiful Evidence, page 122-124.
[[https://edwardtufte.github.io/tufte-css/img/napoleons-march.png]]
#+end_figure
Alternatively, the fullwidth
class can also be applied to the image
directly. However, in this case the resulting image may not truly be
“fullwidth”.
#+ATTR_HTML: :class fullwidth
#+CAPTION: Edward Tufte’s English translation of the Napoleon’s March data visualization. From Beautiful Evidence, page 122-124.
[[https://edwardtufte.github.io/tufte-css/img/napoleons-march.png]]
Experiment and choose depending on your application.
tufte-css
has a notion of image quilts. the examples on tufte-css website are
single images that were created by combining multiple images. However, that
processing was done before linking via html. It’s unclear what, if any,
conveniences tufte-css
provides for image quilts (over and above other
features, since single images can already be included as desired).
However, in ox-tufte
one can create a figure with multiple images.
#+HTML_HEAD_EXTRA: <style> .quiltish img { max-height: 200px; min-height: 100px; } </style>
#+attr_html: :class quiltish
#+CAPTION: caption for multiple images
#+begin_figure
[[./path/to/img1.png]]
[[./path/to/img2.png]]
#+end_figure
h4
heading level is supported in a consistent manner similar toh3
.
Epigraphs and quotes by default occupy only the width of the main content. In
order to get quoted content that extends for the fullwidth add the fullwidth
class with an #+attr_html
annotation.
tufte-css
numbers sidenotes via CSS and as such referring to the same sidenote more than once results in erroneous numbering.ox-tufte
fixes this.- Block margin-notes are supported via src_org{#+begin_marginnote} and src_org{#+end_marginnote}.
- Captions on images are placed below the image (as opposed to in the margin
area) regardless of whether the image is
fullwidth
or not.
- Since code blocks cannot have footnotes/sidenotes in them, they are treated as
if they were using the “fullwidth” class (without having to specify the class
via
#+attr_html
).
- Unlike
ox-html
, inox-tufte
captions on figure special-blocks (the kind used when including multiple images in a block, as in ImageQuilts) are included as figcaptions. Limitation: presently the included caption doesn’t include automated numbering.
There may be some experimental extensions in src/ox-tufte-experimental.css
.
If desired, this css file should be included after src/ox-tufte.css
.
The generated HTML is not compatible with org-info.js. This is because
ox-tufte
customizes the value of org-html-divs
to align it with what’s
expected by tufte-css
.
Code blocks (multiline) currently behave only in a “fullwidth” manner. I.e., if there is sidenote content from previous paragraph, or a block margin-note it will push the code block down.
Additionally, ox-tufte
presently inherits the following limitations from
tufte-css:
- Footnotes/sidenotes cannot contain nested footnotes/sidenotes.
- Sidenotes cannot contain paragraphs, tables etc. (since they are HTML
span
elements). - Captions for
iframe-wrapper
blocks aren’t supported. - The generated HTML must (and does) use an
html5
doctype.
As of [2024-01-12 Fri], org-special-block-extras
is incompatible with
ox-tufte
. As noted in this comment, the incompatibility is primarily due to
hard-coded checks in org-special-block-extras
which are too restrictive and
need to be relaxed.
The behaviour depends on the :footnotes-section-p
option (which uses the value
of org-tufte-include-footnotes-at-bottom
as default).
Because footnotes are transformed to sidenotes they are currently hidden on very
narrow screens (like phones), unless the use manually toggles visibility for
each reference. if you want to include footnotes also at the bottom of the
page, this may be set to t
using setq
:
(require 'ox-tufte)
(setq org-tufte-include-footnotes-at-bottom t)
Or, if you’re using use-package
:
(use-package ox-tufte
:config
(setq org-tufte-include-footnotes-at-bottom t))
This behaviour can also be configured on a per-file basis using:
#+OPTIONS: footnotes-section-p:t
Or, (assuming org-export-allow-bind-keywords
is t
) using below:
#+BIND: org-tufte-include-footnotes-at-bottom t
From tufte-css:
However, on small screens, a margin note is like a sidenote except its viewability-toggle is a symbol rather than a reference number. This document currently uses the symbol ⊕ (⊕), but it’s up to you.
This symbol can be tweaked, by modifying the value of
org-tufte-margin-note-symbol
. Specifically, if this value is set to the empty
string (""
), then margin-notes are always hidden on small screens.
Margin-note visibility color toggle can be tweaked using something like
label.margin-toggle {
color: #a00000;
}
For footnote references, something like below would work
label.sidenote-number,
.sidenote > sup.numeral {
color: #a00000;
}
ox-tufte-init
is no longer needed in addition to loading the library and has been removed.- inline margin-note syntax changes
- inline margin-note-as-macro syntax has been added.
- margin-note-as-link syntax has been un-deprecated.
- all three inline margin-note syntaxes (
-as-babel-call
,-as-macro
,-as-link
) are documented with their respective limitations and quirks.