/Morris

Framework for use with pandoc.

Primary LanguageCSSMIT LicenseMIT

Morris

Make creating documents a pleasure.

license

Pandoc is an incredibly powerful tool – which comes at the cost of being sometimes seemingly too complex. This project aims to lower the hurdles and make document creating an easy thing. Morris provides you with everything you need to quickly generate beatiful documents from your Markdown.

Let's start! It's as easy as:

Usage

make

Features

Morris comes with a makefile you can modify to your liking.

  • make will output a PDF for every .md file in the directory.
  • make both will give you PDF & HTML.
  • make all will output PDF, HTML, Word .docx, OpenOffice .odt, and InDesign .icml. You can also be specific in what you generate by using the format as a make option, e.g. make icml.
  • make clean will delete all generated content in the OUTPUT_PATH folder.

Don't panic when seeing complaints about unknown CSS rules in your CLI: some boilerplate in the morris.css is for generating nice HTML – it is expected to make no sense in printing and vice versa.

  • The HTML output has a simple lightbox enabled when using the .lightbox class on your images.

Your Markdown

Be sure to include some metadata in your Markdown files: Use a YAML block right at the file's beginning. Otherwise you can write in the same way you would always do.

On PDFs

There are different ways to get a PDF from a Markdown document in Pandoc. The default action requires a LaTeX version to be installed. I'm not a big fan of this (using the Markdown/Pandoc combination was to avoid LaTeX in the first place). Pandoc however supports a wide range of other engines, mostly with HTML as an intermediate format. Something which appeals to me much more coming from the web.

Interesting are wkhtmltopdf and weasyprint. Prince might be good, but it's proprietary and unaffordable if you aren't a multi-billion dollar company.
Wkhtmltopdf is the next option here:
However, the default will output an unreadable, smashed pile of text. You need a lot of styling to get something halfway decent. This leads to more problems down the road. Wkthml uses a neolithic version of WebKit which makes it hardly usable (printing is no concern to the WebKit devs). Also none of the newer CSS stuff we got to like in the near past is supported. This already starts with trivial things like CSS variables (aka custom properties). Soon enough you will be ridden with lots of meaningless errors and man, inserting a pagination is an endeavour on loosing your mind. And don't spend your time thinking about hyphenation.

Younger and maybe less atrocious is Weasyprint.
Caveat for Windows users: Weasyprint has a horrible and ridiculous way of installation – you have to install the GTK3 runtime… Hint for Miniconda/Anaconda users: Since weasyprint is Python-based you might have to activate the right environment first (à la activate <py3>).

Once you got through the painful installation weasyprint appears to be quite nice and much more usable than wkhtml.
If you intend to use the makefile you don't need to care anyway, because you need GNU make for that – meaning you should use Cygwin or the Windows Subsystem for Linux WSL (Win10 only).
I have tried to use NMAKE in Windows [by using Qt's Jom, a drop-in replacement], but it is too limited. Don't waste time on that and use WSL instead.

In case you are a Windows user and want to proceed with WSL to use the makefile there is one thing to take care of: You are most likey referecing fonts that aren't available in your Linux subsystem but in Windows natively. How to do that is written down here.

Weasyprint supports CSS' @page rules (designed for paged media so we can easily pass a custom CSS via the usual Pandoc CLI param:

pandoc input.md -o output.pdf --pdf-engine=weasyprint -c morris.css

However, in the end, the sad state of automated layouting solutions didn't got better in the last 10 years. Proper engine support is still lacking many features. So regarding your own CSS: better keep it simple. (Think of styling an email – both has some 90's vibe to it.)

Utilities

You might want to enjoy the possibility to number figures, equations, tables and cross-reference them. This can be done with the pandoc-crossref filter.
With pandoc-plot will turn your code blocks (Matplotlib, MATLAB, Mathematica, graphviz, and more) into embedded figures.

Caution

Be sure you have a recent pandoc version. The versions in the package managers are usually heavily outdated. Also follow the complete weasyprint installation process.

Automation

If you want to have an auto-conversion taking place everytime you push to your repo: That's possible with GitHub Actions!

Trivia

This project was named in honor of William Morris.


Print CSS explained

The biggest difference in understandinng CSS is tied to the viewport and the page model. Whereas on the web we finally have let go of fixed viewport sizes meaning everything is fluid the opposite is true for print: We suddenly have no longer a continuous media, but discrete pages with finite space to fill.

Also there are new concepts which have no analogy on the web.

The @page rule

The page rule lets you define the 'box' into which your content flows.

@page {
  /* use keywords */
  size: A4 landscape; }
@page {
  /* specify dimensions */
  size: 5in 7.5in; }

Understand the page model

Surrounding your main content there are 16 margin boxes defined. Those can be utilized for CSS generated content.

top-left-cornertop-lefttop-centertop-righttop-right-corner
left-topyour contentright-top
left-middleright-middle
left-bottomright-bottom
bottom-left-cornerbottom-leftbottom-centerbottom-rightbottom-right-corner

Page spreads

There is a unique pseudo selector in print to select left and right pages (think of a book).

@page:left {
  margin-left: 5cm; }

@page:right {
  margin-left: 3.2cm; }

The other ones are :first and :blank, which are pretty much self explainatory.

Page breaks

Of course you need to be able to define a page break. The older and mostly supported CSS flavor to achiveve this are page-break-<where>. In CSS3 this has been replaced by break-<where>. Morris supports both.

h1 {
  page-break-before: always; }
h1, h2, h3, h4, h5 {
  page-break-after: avoid; }
table, figure {
  page-break-inside: avoid; }

Counters

Morris is doing page numbers like this:

@bottom-right-corner {
  content: counter(page) " of " counter(pages); }

If you need chapter and/or image numbers you could do it like this:

body {
  counter-reset: chapternum figurenum; }

h1 {
  counter-reset: figurenum; }

h1.title::before {
  counter-increment: chapternum;
  content: counter(chapternum) ". "; }

figcaption::before {
  counter-increment: figurenum;
  content: counter(chapternum) "-" counter(figurenum) ". "; }

Special strings

One of the weirder CSS specs is the string-set property. We can use that to inject CSS content but with a document defined string. To have a living column title you would do:

h1 { 
  string-set: doctitle content(); }

@page:right {
  @top-right {
    content: string(doctitle); }}

Links

If you intend to actually print your document you should take care of the actual link so people could go and type it in. We achieve this by setting:

a:link[href^="http"]::after,
a[href^="http"]:visited::after {
  content: " (" attr(href) ") ";
  font-size: 90%; }

Testing print stylesheets

Testing print stylesheets might seem like a boring task involving of actual printing the page, but there is some possibility of making your live a bit easier:

Firefox

There is a dedicated button to switch into print view:

Firefox print view button

Chrome

Open the devtools, click on the three dots icon, select "More Tools > Rendering". In this tab you can choose to "Emulate CSS media".

Please be aware that this will only help with changes to CSS layout, but not with fragmentation (=laying out the individual pages). You still need to make a PDF for checking that.

Other options

Further reading