Make creating documents a pleasure.
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:
make
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 theOUTPUT_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.
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.
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.)
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.
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.
If you want to have an auto-conversion taking place everytime you push to your repo: That's possible with GitHub Actions!
This project was named in honor of William Morris.
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 lets you define the 'box' into which your content flows.
@page {
/* use keywords */
size: A4 landscape; }
@page {
/* specify dimensions */
size: 5in 7.5in; }
Surrounding your main content there are 16 margin boxes defined. Those can be utilized for CSS generated content.
top-left-corner | top-left | top-center | top-right | top-right-corner |
left-top | your content | right-top | ||
left-middle | right-middle | |||
left-bottom | right-bottom | |||
bottom-left-corner | bottom-left | bottom-center | bottom-right | bottom-right-corner |
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.
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; }
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) ". "; }
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); }}
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 might seem like a boring task involving of actual printing the page, but there is some possibility of making your live a bit easier:
There is a dedicated button to switch into print view:
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.