#+TITLE: ox-tufte #+AUTHOR: The Bayesians Inc. This is an [[https://orgmode.org/manual/Exporting.html#index-export-back_002dend][export backend for Org mode]] that exports buffers to HTML that is compatible with [[https://edwardtufte.github.io/tufte-css/][Tufte CSS]]. * Changes since version 3.x Version 4.x alters some of the internals considerably from the 3.x version. Notably some configuration options have changed. See below for details. ** As of version 4.2.x - 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. ** As of version 4.0.x - Altering variables =org-html-checkbox-type= and =org-html-divs= no longer has any effect. To provide default values for the corresponding options, use variables =org-tufte-html-checkbox-type= and =org-tufte-html-sections= respectively. The properties are still called =:html-checkbox-type= and =:html-divs=, however. - Similarly, =HTML_DOCTYPE= (as well, variable =org-html-doctype= and property =:html-doctype=) and =HTML_CONTAINER= (as well, variable =org-html-container-element= and property =:html-container=) keywords and =html5-fancy= option (as well, variable =org-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 the =html= backend. - New command =org-tufte-convert-region-to-html= added. - Invoking =org-export-string-as= now works ([[https://github.com/ox-tufte/ox-tufte/issues/22][#22]]). - Loading =ox-tufte= now advises =org-export-as=. For advanced uses, the depth of the installed advice is user-configurable via =setopt= (see =org-tufte-export-as-advice-depth=). * Introduction [[https://edwardtufte.github.io/tufte-css/][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= [[https://github.com/ox-tufte/ox-tufte/milestone/1][version 2]] began after noticing that: - =ox-tufte= was broken and didn't faithfully reproduce the =tufte-css= experience. - [[https://github.com/Zilong-Li/org-tufte][org-tufte]] made additional assumptions and was too opinionated. E.g., - deviations from =ox-html= - [[https://github.com/Zilong-Li/org-tufte/blob/404ab1286139ea6cbdc00bb1fb50a0afd9d067de/org-tufte.el#L102][use of katex instead of mathjax]] - [[https://github.com/Zilong-Li/org-tufte/blob/404ab1286139ea6cbdc00bb1fb50a0afd9d067de/org-tufte.el#L87][modified html-template]] - [[https://github.com/Zilong-Li/org-tufte/blob/404ab1286139ea6cbdc00bb1fb50a0afd9d067de/org-tufte.el#L97][automated inclusion of css hosted at third-party location]] =ox-tufte= is still a work-in-progress, but it is being used by at least [[https://weary-travelers.gitlab.io/][one blog]] in "production". Please open an issue if you discover any bugs! ** Compatibility Ox-tufte is compatible and tested with - =tufte-css= [[https://github.com/edwardtufte/tufte-css/releases/tag/v1.8.0][v1.8.0]] - =org-mode= >= 9.5 - =emacs= >= 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! * Installation and Usage You can install ox-tufte using [[https://melpa.org][MELPA]]: #+BEGIN_SRC emacs-lisp (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t) (package-refresh-contents) (package-install 'ox-tufte) #+END_SRC And then in your ~init.el~ (or equivalent): #+BEGIN_SRC emacs-lisp (require 'ox-tufte) #+END_SRC It's important that you download [[https://github.com/edwardtufte/tufte-css][tufte css]] ([[https://github.com/edwardtufte/tufte-css/releases/tag/v1.8.0][v1.8.0]]) and place it on your server (with the fonts). [[https://repology.org/project/emacs:ox-tufte/versions][file:https://repology.org/badge/vertical-allrepos/emacs:ox-tufte.svg]] ** Usage The recommended way to use =ox-tufte= is *with* [[https://orgmode.org/manual/CSS-support.html][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 [[https://github.com/emacs-straight/org-mode/blob/ca873f7fe47546bca19821f1578a6ab95bf5351c/lisp/ox-html.el#L134][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: #+BEGIN_SRC org ,#+HTML_HEAD: ,#+HTML_HEAD: #+END_SRC For usage, when exporting simply select "Tufte HTML" instead of regular HTML export from the export menu (=C-c C-e=). * Features ox-tufte supports *most* of the features from tufte-css, some in different ways than expected, and some extensions. | [[https://edwardtufte.github.io/tufte-css/][Tufte-css concept]] | [[https://orgmode.org/worg/org-syntax.html][Org-mode syntax]] for tufte-css concept | ox-tufte extension | |-----------------------+-------------------------------------------------+---------------------------------------------------| | [[https://edwardtufte.github.io/tufte-css/#fundamentals--sections-and-headers][Sections and Headings]] | Sections and Headings | | | [[https://edwardtufte.github.io/tufte-css/#sidenotes][Sidenotes]] | [[footnotes][Footnotes]] | | | [[https://edwardtufte.github.io/tufte-css/#sidenotes][Margin-notes]] | [[marginnotes-inline][inline babel call]] to [[marginnote]["marginnote" block]] | block margin-notes via "marginnote" special-block | | [[https://edwardtufte.github.io/tufte-css/#epigraphs][Epigraphs]] | [[epigraphs][Quote block]] | | | [[https://edwardtufte.github.io/tufte-css/#figures][iframe wrapper]] | [[figures]["figure"]] org-mode [[https://orgmode.org/org.html#HTML-doctypes][special-block]] | | | [[https://edwardtufte.github.io/tufte-css/#code][Code]] | [[code][Source block]] | | | [[https://edwardtufte.github.io/tufte-css/#imagequilts][ImageQuilts]] | [[quilts][single image or images in"figure" special-block]] | | ** [[https://edwardtufte.github.io/tufte-css/#sidenotes][Sidenotes and margin-notes]] <>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. *** Inline margin-notes <>Since, Org-mode doesn't yet support syntax for inline special blocks ([[https://list.orgmode.org/orgmode/87a6b8pbhg.fsf@posteo.net/][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 [[https://html.spec.whatwg.org/#phrasing-content-2][HTML phrasing content]]). Inline margin-notes are implemented in their most feature-full incarnation as an inline babel call, specifically, to [[marginnote][the "marginnote" block defined below]]. #+name: marginnote #+header: :var input="" #+begin_src elisp :eval yes :exports results :results html replace value (require 'ox-tufte) (ox-tufte--utils-margin-note input) #+end_src If the only content of an inline margin-note is a link to an image, the generated HTML will be malformed. Use the [[https://orgmode.org/manual/Escape-Character.html][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: #+begin_src org 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."). #+end_src 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 #+begin_src org 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.)}}}. #+end_src 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: #+BEGIN_SRC org 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]]. #+END_SRC The reason for not being able to insert links (or images) using this syntax is an org syntax limitation. *** Block margin-notes There is also support for "block" margin-notes, which are margin-notes that can contain "block" elements ([[https://html.spec.whatwg.org/#flow-content-2][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_src org ,#+begin_marginnote This is a block level margin-note. - item 1 - item 2 ,#+end_marginnote #+end_src The block marginnote is displayed to the right side of the paragraph following it. In case a block margin-note is needed in [[https://orgmode.org/worg/org-syntax.html#Zeroth_section][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_src org ,#+begin_zeroth-section ,#+begin_marginnote This is a block level margin-note. - item 1 - item 2 ,#+end_marginnote ,#+end_zeroth-section #+end_src ** <>[[https://edwardtufte.github.io/tufte-css/#epigraphs][Epigraphs]] and [[https://orgmode.org/manual/Paragraphs.html#index-BEGIN_005fVERSE][quotes]] - Anything within =#+begin_epigraph= and =#+end_epigraph= becomes an epigraph (which is a collection of one or more quoted blocks). For example: #+begin_src org ,#+begin_epigraph ,#+name: quote-1 ,#+caption: Richard P. Feynman, @@html:“What Do You Care What Other People Think?”@@ ,#+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:Henri Matisse Dessins: thèmes et variations@@ (Paris, 1943), 37 ,#+begin_quote I do not paint things, I paint only the differences between things. ,#+end_quote ,#+end_epigraph #+end_src - =ox-tufte= also adds support for =#+CAPTION= on [[https://orgmode.org/manual/Paragraphs.html#index-BEGIN_005fVERSE][org-mode =quote= and =verse= blocks]]. ** <>[[https://edwardtufte.github.io/tufte-css/#code][Code]] =ox-tufte= uses =ox-html= to export [[https://orgmode.org/manual/Literal-Examples.html][code fragments]] to HTML (without any alteration). =ox-html= and [[https://elpa.nongnu.org/nongnu/htmlize.html][=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 [[https://melpa.org/#/plan9-theme][=plan9-theme=]] which can be installed from Melpa via something like: #+begin_src elisp (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t) (package-refresh-contents) (package-install 'plan9-theme) #+end_src And then in your =init.el= or equivalent, load it using: src_elisp{(load-theme 'plan9 t)}. ** <>Figures and iframes To use =tufte-css='s =iframe-wrapper= class, one can do something like below: #+begin_src org ,#+ATTR_HTML: :class iframe-wrapper ,#+begin_figure @@html:@@ ,#+end_figure #+end_src To have fullwidth figures: #+begin_src org ,#+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 #+end_src Alternatively, the =fullwidth= class can also be applied to the image directly. However, in this case the resulting image may not truly be "fullwidth". #+begin_src org ,#+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]] #+end_src Experiment and choose depending on your application. ** <>ImageQuilts =tufte-css= has a notion of image quilts. [[https://edwardtufte.github.io/tufte-css/#imagequilts][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 [[figures][single images can already be included as desired]]). However, in =ox-tufte= one can create a figure with multiple images. #+begin_src org ,#+HTML_HEAD_EXTRA: ,#+attr_html: :class quiltish ,#+CAPTION: caption for multiple images ,#+begin_figure [[./path/to/img1.png]] [[./path/to/img2.png]] ,#+end_figure #+end_src ** Deviations and Extensions (from =tufte-css= and =ox-html=) *** Sections and Headings - =h4= heading level is supported in a consistent manner similar to =h3=. *** Epigraphs 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. *** Sidenotes and margin-notes - =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}. *** Figures - Captions on images are placed below the image (as opposed to in the margin area) regardless of whether the image is =fullwidth= or not. *** Code - 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=). *** ImageQuilts - Unlike =ox-html=, in =ox-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. ** Experimental 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=. * Limitations ** Incompatibility with =org-info.js= The generated HTML is not compatible with [[https://orgmode.org/worg/code/org-info-js/][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 are only fullwidth 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. ** Constraints inherited from =tufte-css= Additionally, =ox-tufte= presently inherits the following limitations from [[https://edwardtufte.github.io/tufte-css/][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. ** Incompatibility with =org-special-block-extras= As of [2024-01-12 Fri], =org-special-block-extras= is incompatible with =ox-tufte=. As noted in [[https://github.com/ox-tufte/ox-tufte/issues/20#issuecomment-1880626278][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. * Customization ** Footnotes section at bottom 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=: #+begin_src elisp (require 'ox-tufte) (setq org-tufte-include-footnotes-at-bottom t) #+end_src Or, if you're using =use-package=: #+begin_src elisp (use-package ox-tufte :config (setq org-tufte-include-footnotes-at-bottom t)) #+end_src This behaviour can also be configured on a per-file basis using: #+begin_src org ,#+OPTIONS: footnotes-section-p:t #+end_src Or, (assuming =org-export-allow-bind-keywords= is =t=) using below: #+begin_src org ,#+BIND: org-tufte-include-footnotes-at-bottom t #+end_src ** Margin-note symbol and visibility on small screens From [[https://edwardtufte.github.io/tufte-css/][tufte-css]]: #+begin_quote 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. #+end_quote 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. ** Color of margin-note visibility-toggle and footnote-references Margin-note visibility color toggle can be tweaked using something like #+begin_src css label.margin-toggle { color: #a00000; } #+end_src For footnote references, something like below would work #+begin_src css label.sidenote-number, .sidenote > sup.numeral { color: #a00000; } #+end_src * References - https://edwardtufte.github.io/tufte-css/ - https://gitlab.com/snippets/22309 * CHANGELOG :ARCHIVE: ** Changes since version 2.x :PROPERTIES: :ARCHIVE_TIME: 2024-01-12 Fri 15:14 :END: - =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.